|
Packit Service |
db8df9 |
/*
|
|
Packit Service |
db8df9 |
* Intel(R) Enclosure LED Utilities
|
|
Packit Service |
db8df9 |
* Copyright (C) 2009-2019 Intel Corporation.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* This program is free software; you can redistribute it and/or modify it
|
|
Packit Service |
db8df9 |
* under the terms and conditions of the GNU General Public License,
|
|
Packit Service |
db8df9 |
* version 2, as published by the Free Software Foundation.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
Packit Service |
db8df9 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
Packit Service |
db8df9 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
Packit Service |
db8df9 |
* more details.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* You should have received a copy of the GNU General Public License along with
|
|
Packit Service |
db8df9 |
* this program; if not, write to the Free Software Foundation, Inc.,
|
|
Packit Service |
db8df9 |
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
#include <dirent.h>
|
|
Packit Service |
db8df9 |
#include <errno.h>
|
|
Packit Service |
db8df9 |
#include <fcntl.h>
|
|
Packit Service |
db8df9 |
#include <limits.h>
|
|
Packit Service |
db8df9 |
#include <stdint.h>
|
|
Packit Service |
db8df9 |
#include <stdio.h>
|
|
Packit Service |
db8df9 |
#include <stdlib.h>
|
|
Packit Service |
db8df9 |
#include <string.h>
|
|
Packit Service |
db8df9 |
#include <sys/stat.h>
|
|
Packit Service |
db8df9 |
#include <unistd.h>
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
#if _HAVE_DMALLOC_H
|
|
Packit Service |
db8df9 |
#include <dmalloc.h>
|
|
Packit Service |
db8df9 |
#endif
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
#include <scsi/sg_lib.h>
|
|
Packit Service |
db8df9 |
#include <scsi/sg_cmds_extra.h>
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
#include "cntrl.h"
|
|
Packit Service |
db8df9 |
#include "config.h"
|
|
Packit Service |
db8df9 |
#include "enclosure.h"
|
|
Packit Service |
db8df9 |
#include "list.h"
|
|
Packit Service |
db8df9 |
#include "scsi.h"
|
|
Packit Service |
db8df9 |
#include "ses.h"
|
|
Packit Service |
db8df9 |
#include "status.h"
|
|
Packit Service |
db8df9 |
#include "sysfs.h"
|
|
Packit Service |
db8df9 |
#include "utils.h"
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static int debug = 0;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static int get_ses_page(int fd, struct ses_page *p, int pg_code)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
int ret;
|
|
Packit Service |
db8df9 |
int retry_count = 3;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
do {
|
|
Packit Service |
db8df9 |
ret = sg_ll_receive_diag(fd, 1, pg_code, p->buf, sizeof(p->buf),
|
|
Packit Service |
db8df9 |
0, debug);
|
|
Packit Service |
db8df9 |
} while (ret && retry_count--);
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (!ret)
|
|
Packit Service |
db8df9 |
p->len = (p->buf[2] << 8) + p->buf[3] + 4;
|
|
Packit Service |
db8df9 |
return ret;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static int process_page1(struct ses_pages *sp)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
int num_encl; /* number of subenclosures */
|
|
Packit Service |
db8df9 |
unsigned char *ed; /* Enclosure Descriptor */
|
|
Packit Service |
db8df9 |
int len = 0;
|
|
Packit Service |
db8df9 |
int sum_headers = 0; /* Number of Type descriptor headers */
|
|
Packit Service |
db8df9 |
int i = 0;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/* How many enclosures is in the main enclosure? */
|
|
Packit Service |
db8df9 |
num_encl = sp->page1->buf[1] + 1;
|
|
Packit Service |
db8df9 |
/* Go to Enclosure Descriptor */
|
|
Packit Service |
db8df9 |
ed = sp->page1->buf + 8;
|
|
Packit Service |
db8df9 |
for (i = 0; i < num_encl; i++, ed += len) {
|
|
Packit Service |
db8df9 |
if (ed + 3 > sp->page1->buf + sp->page1->len) {
|
|
Packit Service |
db8df9 |
log_debug
|
|
Packit Service |
db8df9 |
("SES: Error, response pare 1 truncated at %d\n",
|
|
Packit Service |
db8df9 |
i);
|
|
Packit Service |
db8df9 |
return 1;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
sum_headers += ed[2];
|
|
Packit Service |
db8df9 |
len = ed[3] + 4;
|
|
Packit Service |
db8df9 |
if (len < 40) {
|
|
Packit Service |
db8df9 |
log_debug("SES: Response too short for page 1\n");
|
|
Packit Service |
db8df9 |
continue;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
sp->page1_types = (struct type_descriptor_header *)ed;
|
|
Packit Service |
db8df9 |
sp->page1_types_len = sum_headers;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/* ed is on type descr header */
|
|
Packit Service |
db8df9 |
for (i = 0; i < sum_headers; i++, ed += 4) {
|
|
Packit Service |
db8df9 |
if (ed > sp->page1->buf + sp->page1->len) {
|
|
Packit Service |
db8df9 |
log_debug("SES: Response page 1 truncated at %d\n", i);
|
|
Packit Service |
db8df9 |
return 1;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
return 0;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static struct ses_pages *ses_init(void)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct ses_pages *sp;
|
|
Packit Service |
db8df9 |
sp = calloc(1, sizeof(*sp));
|
|
Packit Service |
db8df9 |
if (!sp)
|
|
Packit Service |
db8df9 |
return NULL;
|
|
Packit Service |
db8df9 |
sp->page1 = calloc(1, sizeof(struct ses_page));
|
|
Packit Service |
db8df9 |
if (!sp->page1)
|
|
Packit Service |
db8df9 |
goto sp1;
|
|
Packit Service |
db8df9 |
sp->page2 = calloc(1, sizeof(struct ses_page));
|
|
Packit Service |
db8df9 |
if (!sp->page2)
|
|
Packit Service |
db8df9 |
goto sp2;
|
|
Packit Service |
db8df9 |
return sp;
|
|
Packit Service |
db8df9 |
sp2:
|
|
Packit Service |
db8df9 |
free(sp->page1);
|
|
Packit Service |
db8df9 |
sp1:
|
|
Packit Service |
db8df9 |
free(sp);
|
|
Packit Service |
db8df9 |
return NULL;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static void ses_free(struct ses_pages *sp)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
if (!sp)
|
|
Packit Service |
db8df9 |
return;
|
|
Packit Service |
db8df9 |
free(sp->page1);
|
|
Packit Service |
db8df9 |
free(sp->page2);
|
|
Packit Service |
db8df9 |
free(sp->page10);
|
|
Packit Service |
db8df9 |
free(sp);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static void dump_p10(unsigned char *p)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
int i;
|
|
Packit Service |
db8df9 |
printf("----------------------------------------------\n");
|
|
Packit Service |
db8df9 |
for (i = 0; i < 8; i++, p += 16) {
|
|
Packit Service |
db8df9 |
printf("%p: %02x %02x %02x %02x %02x %02x %02x " \
|
|
Packit Service |
db8df9 |
"%02x %02x %02x %02x %02x %02x %02x %02x %02x\n", (void *)p,
|
|
Packit Service |
db8df9 |
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
|
|
Packit Service |
db8df9 |
p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static int enclosure_open(const struct enclosure_device *enclosure)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
int fd = -1;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (enclosure->dev_path)
|
|
Packit Service |
db8df9 |
fd = open(enclosure->dev_path, O_RDWR);
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
return fd;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static int enclosure_load_pages(struct enclosure_device *enclosure)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
int ret;
|
|
Packit Service |
db8df9 |
int fd;
|
|
Packit Service |
db8df9 |
struct ses_pages *sp;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (enclosure->ses_pages)
|
|
Packit Service |
db8df9 |
return 0;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
fd = enclosure_open(enclosure);
|
|
Packit Service |
db8df9 |
if (fd == -1)
|
|
Packit Service |
db8df9 |
return 1;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
sp = ses_init();
|
|
Packit Service |
db8df9 |
if (!sp) {
|
|
Packit Service |
db8df9 |
ret = 1;
|
|
Packit Service |
db8df9 |
goto end;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/* Read configuration. */
|
|
Packit Service |
db8df9 |
ret = get_ses_page(fd, sp->page1, ENCL_CFG_DIAG_STATUS);
|
|
Packit Service |
db8df9 |
if (ret)
|
|
Packit Service |
db8df9 |
goto end;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
ret = process_page1(sp);
|
|
Packit Service |
db8df9 |
if (ret)
|
|
Packit Service |
db8df9 |
goto end;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/* Get Enclosure Status */
|
|
Packit Service |
db8df9 |
ret = get_ses_page(fd, sp->page2, ENCL_CTRL_DIAG_STATUS);
|
|
Packit Service |
db8df9 |
end:
|
|
Packit Service |
db8df9 |
close(fd);
|
|
Packit Service |
db8df9 |
if (ret)
|
|
Packit Service |
db8df9 |
ses_free(sp);
|
|
Packit Service |
db8df9 |
else
|
|
Packit Service |
db8df9 |
enclosure->ses_pages = sp;
|
|
Packit Service |
db8df9 |
return ret;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static int enclosure_load_page10(struct enclosure_device *enclosure)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
int ret;
|
|
Packit Service |
db8df9 |
int fd;
|
|
Packit Service |
db8df9 |
struct ses_page *p;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (enclosure->ses_pages && enclosure->ses_pages->page10)
|
|
Packit Service |
db8df9 |
return 0;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
ret = enclosure_load_pages(enclosure);
|
|
Packit Service |
db8df9 |
if (ret)
|
|
Packit Service |
db8df9 |
return ret;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
fd = enclosure_open(enclosure);
|
|
Packit Service |
db8df9 |
if (fd == -1)
|
|
Packit Service |
db8df9 |
return 1;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
p = calloc(1, sizeof(struct ses_page));
|
|
Packit Service |
db8df9 |
if (!p) {
|
|
Packit Service |
db8df9 |
ret = 1;
|
|
Packit Service |
db8df9 |
goto end;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/* Additional Element Status */
|
|
Packit Service |
db8df9 |
ret = get_ses_page(fd, p, ENCL_ADDITIONAL_EL_STATUS);
|
|
Packit Service |
db8df9 |
end:
|
|
Packit Service |
db8df9 |
close(fd);
|
|
Packit Service |
db8df9 |
if (ret)
|
|
Packit Service |
db8df9 |
free(p);
|
|
Packit Service |
db8df9 |
else
|
|
Packit Service |
db8df9 |
enclosure->ses_pages->page10 = p;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
return ret;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static void enclosure_free_pages(struct enclosure_device *enclosure)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
ses_free(enclosure->ses_pages);
|
|
Packit Service |
db8df9 |
enclosure->ses_pages = NULL;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static void print_page10(struct ses_pages *sp)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
unsigned char *ai = sp->page10->buf + 8;
|
|
Packit Service |
db8df9 |
int i = 0, len = 0, eip = 0;
|
|
Packit Service |
db8df9 |
unsigned char *sas = NULL;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
while (ai < sp->page10->buf + sp->page10->len) {
|
|
Packit Service |
db8df9 |
printf("%s()[%d]: Inv: %d, EIP: %d, Proto: 0x%04x\n", __func__,
|
|
Packit Service |
db8df9 |
i++, ((ai[0] & 0x80) >> 7), ((ai[0] & 0x10) >> 4),
|
|
Packit Service |
db8df9 |
(unsigned int) (ai[0] & 0xf));
|
|
Packit Service |
db8df9 |
printf("\tDescriptor len (x-1): %d\n", ai[1] + 1);
|
|
Packit Service |
db8df9 |
eip = ai[0] & 0x10;
|
|
Packit Service |
db8df9 |
if (eip)
|
|
Packit Service |
db8df9 |
printf("\tElement Index: %d\n", ai[3]);
|
|
Packit Service |
db8df9 |
len = ai[1] + 2;
|
|
Packit Service |
db8df9 |
if ((ai[0] & 0xf) == SCSI_PROTOCOL_SAS) {
|
|
Packit Service |
db8df9 |
if (eip)
|
|
Packit Service |
db8df9 |
sas = ai + 4;
|
|
Packit Service |
db8df9 |
else
|
|
Packit Service |
db8df9 |
sas = ai + 2;
|
|
Packit Service |
db8df9 |
printf("\tProtocol SAS:\n");
|
|
Packit Service |
db8df9 |
printf("\tNumber of phy descriptors: %d\n", sas[0]);
|
|
Packit Service |
db8df9 |
printf("\tNot all phys: %d, descriptor type: 0x%1x\n",
|
|
Packit Service |
db8df9 |
(sas[1] & 1), ((sas[1] & 0xc0) >> 6));
|
|
Packit Service |
db8df9 |
if (eip) {
|
|
Packit Service |
db8df9 |
printf("\tDevice slot number: %d\n", sas[3]);
|
|
Packit Service |
db8df9 |
sas += 2;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
sas += 2;
|
|
Packit Service |
db8df9 |
printf("\tDevice type: 0x%01x\n",
|
|
Packit Service |
db8df9 |
(unsigned int)((sas[0] & 0x70) >> 4));
|
|
Packit Service |
db8df9 |
printf("\tSMP Initiator Port: 0x%01x\n",
|
|
Packit Service |
db8df9 |
(unsigned int)((sas[2] & 2) >> 1));
|
|
Packit Service |
db8df9 |
printf("\tSTP Initiator Port: 0x%01x\n",
|
|
Packit Service |
db8df9 |
(unsigned int)((sas[2] & 4) >> 2));
|
|
Packit Service |
db8df9 |
printf("\tSSP Initiator Port: 0x%01x\n",
|
|
Packit Service |
db8df9 |
(unsigned int)((sas[2] & 8) >> 3));
|
|
Packit Service |
db8df9 |
printf("\tSATA DEVICE: 0x%01x\n",
|
|
Packit Service |
db8df9 |
(unsigned int)(sas[3] & 1));
|
|
Packit Service |
db8df9 |
printf("\tSMP Target Port: 0x%01x\n",
|
|
Packit Service |
db8df9 |
(unsigned int)((sas[3] & 2) >> 1));
|
|
Packit Service |
db8df9 |
printf("\tSTP Target Port: 0x%01x\n",
|
|
Packit Service |
db8df9 |
(unsigned int)((sas[3] & 4) >> 2));
|
|
Packit Service |
db8df9 |
printf("\tSSP Target Port: 0x%01x\n",
|
|
Packit Service |
db8df9 |
(unsigned int)((sas[3] & 8) >> 3));
|
|
Packit Service |
db8df9 |
printf("\tSATA Port Selector: 0x%01x\n",
|
|
Packit Service |
db8df9 |
(unsigned int)((sas[3] & 0X80) >> 7));
|
|
Packit Service |
db8df9 |
printf
|
|
Packit Service |
db8df9 |
("\tAttached SAS Address: 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
|
|
Packit Service |
db8df9 |
sas[4], sas[5], sas[6], sas[7], sas[8], sas[9],
|
|
Packit Service |
db8df9 |
sas[10], sas[11]);
|
|
Packit Service |
db8df9 |
printf
|
|
Packit Service |
db8df9 |
("\tSAS Address: 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
|
|
Packit Service |
db8df9 |
sas[12], sas[13], sas[14], sas[15], sas[16],
|
|
Packit Service |
db8df9 |
sas[17], sas[18], sas[19]);
|
|
Packit Service |
db8df9 |
printf("\tPHY Identified: 0x%01x\n", sas[20]);
|
|
Packit Service |
db8df9 |
} else
|
|
Packit Service |
db8df9 |
printf("\tProtocol not SAS: 0x%02x, skipping\n",
|
|
Packit Service |
db8df9 |
(unsigned int)(ai[0] & 0xf));
|
|
Packit Service |
db8df9 |
/* */
|
|
Packit Service |
db8df9 |
ai += len;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
return;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static enum ibpi_pattern ibpi_to_ses(enum ibpi_pattern ibpi)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
switch (ibpi) {
|
|
Packit Service |
db8df9 |
case IBPI_PATTERN_UNKNOWN:
|
|
Packit Service |
db8df9 |
case IBPI_PATTERN_ONESHOT_NORMAL:
|
|
Packit Service |
db8df9 |
case IBPI_PATTERN_NORMAL:
|
|
Packit Service |
db8df9 |
return SES_REQ_OK;
|
|
Packit Service |
db8df9 |
case IBPI_PATTERN_FAILED_ARRAY:
|
|
Packit Service |
db8df9 |
return SES_REQ_IFA;
|
|
Packit Service |
db8df9 |
case IBPI_PATTERN_DEGRADED:
|
|
Packit Service |
db8df9 |
return SES_REQ_ICA;
|
|
Packit Service |
db8df9 |
case IBPI_PATTERN_REBUILD:
|
|
Packit Service |
db8df9 |
return SES_REQ_REBUILD;
|
|
Packit Service |
db8df9 |
case IBPI_PATTERN_FAILED_DRIVE:
|
|
Packit Service |
db8df9 |
return SES_REQ_FAULT;
|
|
Packit Service |
db8df9 |
case IBPI_PATTERN_LOCATE:
|
|
Packit Service |
db8df9 |
return SES_REQ_IDENT;
|
|
Packit Service |
db8df9 |
case IBPI_PATTERN_HOTSPARE:
|
|
Packit Service |
db8df9 |
return SES_REQ_HOSTSPARE;
|
|
Packit Service |
db8df9 |
case IBPI_PATTERN_PFA:
|
|
Packit Service |
db8df9 |
return SES_REQ_PRDFAIL;
|
|
Packit Service |
db8df9 |
default:
|
|
Packit Service |
db8df9 |
return ibpi;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static int ses_set_message(enum ibpi_pattern ibpi, struct ses_slot_ctrl_elem *el)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct ses_slot_ctrl_elem msg;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
memset(&msg, 0, sizeof(msg));
|
|
Packit Service |
db8df9 |
if (ibpi == IBPI_PATTERN_LOCATE_OFF) {
|
|
Packit Service |
db8df9 |
/*
|
|
Packit Service |
db8df9 |
* For locate_off we don't set a new state, just clear the
|
|
Packit Service |
db8df9 |
* IDENT bit and the bits that are reserved or have different
|
|
Packit Service |
db8df9 |
* meanings in Status and Control pages (RQST ACTIVE and
|
|
Packit Service |
db8df9 |
* RQST MISSING).
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
_clr_ident(el->b);
|
|
Packit Service |
db8df9 |
el->b2 &= 0x4e;
|
|
Packit Service |
db8df9 |
el->b3 &= 0x3c;
|
|
Packit Service |
db8df9 |
return 0;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
switch (ibpi_to_ses(ibpi)) {
|
|
Packit Service |
db8df9 |
case SES_REQ_ABORT:
|
|
Packit Service |
db8df9 |
_set_abrt(msg.b);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case SES_REQ_REBUILD:
|
|
Packit Service |
db8df9 |
_set_rebuild(msg.b);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case SES_REQ_IFA:
|
|
Packit Service |
db8df9 |
_set_ifa(msg.b);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case SES_REQ_ICA:
|
|
Packit Service |
db8df9 |
_set_ica(msg.b);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case SES_REQ_CONS_CHECK:
|
|
Packit Service |
db8df9 |
_set_cons_check(msg.b);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case SES_REQ_HOSTSPARE:
|
|
Packit Service |
db8df9 |
_set_hspare(msg.b);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case SES_REQ_RSVD_DEV:
|
|
Packit Service |
db8df9 |
_set_rsvd_dev(msg.b);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case SES_REQ_OK:
|
|
Packit Service |
db8df9 |
_set_ok(msg.b);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case SES_REQ_IDENT:
|
|
Packit Service |
db8df9 |
_set_ident(msg.b);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case SES_REQ_RM:
|
|
Packit Service |
db8df9 |
_set_rm(msg.b);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case SES_REQ_INS:
|
|
Packit Service |
db8df9 |
_set_ins(msg.b);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case SES_REQ_MISSING:
|
|
Packit Service |
db8df9 |
_set_miss(msg.b);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case SES_REQ_DNR:
|
|
Packit Service |
db8df9 |
_set_dnr(msg.b);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case SES_REQ_ACTIVE:
|
|
Packit Service |
db8df9 |
_set_actv(msg.b);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case SES_REQ_EN_BB:
|
|
Packit Service |
db8df9 |
_set_enbb(msg.b);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case SES_REQ_EN_BA:
|
|
Packit Service |
db8df9 |
_set_enba(msg.b);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case SES_REQ_DEV_OFF:
|
|
Packit Service |
db8df9 |
_set_off(msg.b);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case SES_REQ_FAULT:
|
|
Packit Service |
db8df9 |
_set_fault(msg.b);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case SES_REQ_PRDFAIL:
|
|
Packit Service |
db8df9 |
_set_prdfail(msg.b);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
default:
|
|
Packit Service |
db8df9 |
return 1;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
*el = msg;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
return 0;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static int ses_write_msg(enum ibpi_pattern ibpi, struct block_device *device)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct ses_pages *sp = device->enclosure->ses_pages;
|
|
Packit Service |
db8df9 |
int idx = device->encl_index;
|
|
Packit Service |
db8df9 |
/* Move do descriptors */
|
|
Packit Service |
db8df9 |
struct ses_slot_ctrl_elem *descriptors = (void *)(sp->page2->buf + 8);
|
|
Packit Service |
db8df9 |
int i;
|
|
Packit Service |
db8df9 |
struct ses_slot_ctrl_elem *desc_element = NULL;
|
|
Packit Service |
db8df9 |
element_type local_element_type = SES_UNSPECIFIED;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
for (i = 0; i < sp->page1_types_len; i++) {
|
|
Packit Service |
db8df9 |
struct type_descriptor_header *t = &sp->page1_types[i];
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
descriptors++; /* At first, skip overall header. */
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (t->element_type == SES_DEVICE_SLOT ||
|
|
Packit Service |
db8df9 |
t->element_type == SES_ARRAY_DEVICE_SLOT) {
|
|
Packit Service |
db8df9 |
if (local_element_type < t->element_type &&
|
|
Packit Service |
db8df9 |
t->num_of_elements > idx) {
|
|
Packit Service |
db8df9 |
local_element_type = t->element_type;
|
|
Packit Service |
db8df9 |
desc_element = &descriptors[idx];
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
} else {
|
|
Packit Service |
db8df9 |
/*
|
|
Packit Service |
db8df9 |
* Device Slot and Array Device Slot elements are
|
|
Packit Service |
db8df9 |
* always first on the type descriptor header list
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
descriptors += t->num_of_elements;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (desc_element) {
|
|
Packit Service |
db8df9 |
int ret = ses_set_message(ibpi, desc_element);
|
|
Packit Service |
db8df9 |
if (ret)
|
|
Packit Service |
db8df9 |
return ret;
|
|
Packit Service |
db8df9 |
/* keep PRDFAIL, clear rest */
|
|
Packit Service |
db8df9 |
desc_element->common_control &= 0x40;
|
|
Packit Service |
db8df9 |
/* set select */
|
|
Packit Service |
db8df9 |
desc_element->common_control |= 0x80;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/* second byte is valid only for Array Device Slot */
|
|
Packit Service |
db8df9 |
if (local_element_type != SES_ARRAY_DEVICE_SLOT)
|
|
Packit Service |
db8df9 |
desc_element->array_slot_control = 0;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
return 0;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
return 1;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static int ses_send_diag(struct enclosure_device *enclosure)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
int ret;
|
|
Packit Service |
db8df9 |
int fd;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
fd = enclosure_open(enclosure);
|
|
Packit Service |
db8df9 |
if (fd == -1)
|
|
Packit Service |
db8df9 |
return 1;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
ret = sg_ll_send_diag(fd, 0, 1, 0, 0, 0, 0,
|
|
Packit Service |
db8df9 |
enclosure->ses_pages->page2->buf,
|
|
Packit Service |
db8df9 |
enclosure->ses_pages->page2->len,
|
|
Packit Service |
db8df9 |
0, debug);
|
|
Packit Service |
db8df9 |
close(fd);
|
|
Packit Service |
db8df9 |
return ret;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static char *get_drive_end_dev(const char *path)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
char *s, *c, *p;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
c = strstr(path, "end_device");
|
|
Packit Service |
db8df9 |
if (!c)
|
|
Packit Service |
db8df9 |
return NULL;
|
|
Packit Service |
db8df9 |
s = strchr(c, '/');
|
|
Packit Service |
db8df9 |
if (!s)
|
|
Packit Service |
db8df9 |
return NULL;
|
|
Packit Service |
db8df9 |
p = calloc(s - c + 1, sizeof(*p));
|
|
Packit Service |
db8df9 |
if (!p)
|
|
Packit Service |
db8df9 |
return NULL;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
strncpy(p, c, s - c);
|
|
Packit Service |
db8df9 |
return p;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static uint64_t get_drive_sas_addr(const char *path)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
uint64_t ret = 0;
|
|
Packit Service |
db8df9 |
size_t size = strlen(path) * 2;
|
|
Packit Service |
db8df9 |
char *buff, *end_dev;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/* Make big buffer. */
|
|
Packit Service |
db8df9 |
buff = malloc(size + 1);
|
|
Packit Service |
db8df9 |
if (!buff)
|
|
Packit Service |
db8df9 |
return ret;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
end_dev = get_drive_end_dev(path);
|
|
Packit Service |
db8df9 |
if (!end_dev) {
|
|
Packit Service |
db8df9 |
free(buff);
|
|
Packit Service |
db8df9 |
return ret;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
snprintf(buff, size, "/sys/class/sas_end_device/%s/device/sas_device/%s",
|
|
Packit Service |
db8df9 |
end_dev, end_dev);
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
ret = get_uint64(buff, ret, "sas_address");
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
free(end_dev);
|
|
Packit Service |
db8df9 |
free(buff);
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
return ret;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static int get_encl_slot(struct block_device *device)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct ses_pages *sp;
|
|
Packit Service |
db8df9 |
unsigned char *add_desc = NULL;
|
|
Packit Service |
db8df9 |
unsigned char *ap = NULL, *addr_p = NULL;
|
|
Packit Service |
db8df9 |
int i, j, len = 0;
|
|
Packit Service |
db8df9 |
uint64_t addr, addr_cmp;
|
|
Packit Service |
db8df9 |
int idx;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/* try to get slot from sysfs */
|
|
Packit Service |
db8df9 |
idx = get_int(device->cntrl_path, -1, "slot");
|
|
Packit Service |
db8df9 |
if (idx != -1)
|
|
Packit Service |
db8df9 |
return idx;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/*
|
|
Packit Service |
db8df9 |
* Older kernels may not have the "slot" sysfs attribute,
|
|
Packit Service |
db8df9 |
* fallback to Page10 method.
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
if (enclosure_load_page10(device->enclosure))
|
|
Packit Service |
db8df9 |
return -1;
|
|
Packit Service |
db8df9 |
sp = device->enclosure->ses_pages;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
addr = get_drive_sas_addr(device->sysfs_path);
|
|
Packit Service |
db8df9 |
if (!addr)
|
|
Packit Service |
db8df9 |
return -1;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (debug)
|
|
Packit Service |
db8df9 |
print_page10(sp);
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/* Check Page10 for address. Extract index. */
|
|
Packit Service |
db8df9 |
ap = add_desc = sp->page10->buf + 8;
|
|
Packit Service |
db8df9 |
for (i = 0; i < sp->page1_types_len; i++) {
|
|
Packit Service |
db8df9 |
struct type_descriptor_header *t = &sp->page1_types[i];
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (t->element_type == SES_DEVICE_SLOT ||
|
|
Packit Service |
db8df9 |
t->element_type == SES_ARRAY_DEVICE_SLOT) {
|
|
Packit Service |
db8df9 |
for (j = 0; j < t->num_of_elements; j++, ap += len) {
|
|
Packit Service |
db8df9 |
if (debug)
|
|
Packit Service |
db8df9 |
dump_p10(ap);
|
|
Packit Service |
db8df9 |
/* Get Additional Element Status Descriptor */
|
|
Packit Service |
db8df9 |
/* length (x-1) */
|
|
Packit Service |
db8df9 |
len = ap[1] + 2;
|
|
Packit Service |
db8df9 |
if ((ap[0] & 0xf) != SCSI_PROTOCOL_SAS)
|
|
Packit Service |
db8df9 |
continue; /* need SAS PROTO */
|
|
Packit Service |
db8df9 |
/* It is a SAS protocol, go on */
|
|
Packit Service |
db8df9 |
if ((ap[0] & 0x10)) /* Check EIP */
|
|
Packit Service |
db8df9 |
addr_p = ap + 8;
|
|
Packit Service |
db8df9 |
else
|
|
Packit Service |
db8df9 |
addr_p = ap + 4;
|
|
Packit Service |
db8df9 |
/* Process only PHY 0 descriptor. */
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/* Convert be64 to le64 */
|
|
Packit Service |
db8df9 |
addr_cmp = ((uint64_t)addr_p[12] << 8*7) |
|
|
Packit Service |
db8df9 |
((uint64_t)addr_p[13] << 8*6) |
|
|
Packit Service |
db8df9 |
((uint64_t)addr_p[14] << 8*5) |
|
|
Packit Service |
db8df9 |
((uint64_t)addr_p[15] << 8*4) |
|
|
Packit Service |
db8df9 |
((uint64_t)addr_p[16] << 8*3) |
|
|
Packit Service |
db8df9 |
((uint64_t)addr_p[17] << 8*2) |
|
|
Packit Service |
db8df9 |
((uint64_t)addr_p[18] << 8*1) |
|
|
Packit Service |
db8df9 |
((uint64_t)addr_p[19]);
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (addr == addr_cmp) {
|
|
Packit Service |
db8df9 |
idx = ap[0] & 0x10 ? ap[3] : j;
|
|
Packit Service |
db8df9 |
return idx;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
} else {
|
|
Packit Service |
db8df9 |
/*
|
|
Packit Service |
db8df9 |
* Device Slot and Array Device Slot elements are
|
|
Packit Service |
db8df9 |
* always first on the type descriptor header list
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
return -1;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static int _slot_match(const char *slot_path, const char *device_path)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
char temp[PATH_MAX], link[PATH_MAX];
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
snprintf(temp, sizeof(temp), "%s/device", slot_path);
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (realpath(temp, link) == NULL)
|
|
Packit Service |
db8df9 |
return 0;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
return strncmp(link, device_path, strlen(link)) == 0;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static char *_slot_find(const char *enclo_path, const char *device_path)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct list dir;
|
|
Packit Service |
db8df9 |
char *temp, *result = NULL;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (scan_dir(enclo_path, &dir) == 0) {
|
|
Packit Service |
db8df9 |
list_for_each(&dir, temp) {
|
|
Packit Service |
db8df9 |
if (_slot_match(temp, device_path)) {
|
|
Packit Service |
db8df9 |
result = str_dup(temp);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
list_erase(&dir;;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
return result;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
int scsi_get_enclosure(struct block_device *device)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct enclosure_device *encl;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (!device || !device->sysfs_path)
|
|
Packit Service |
db8df9 |
return 0;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
list_for_each(sysfs_get_enclosure_devices(), encl) {
|
|
Packit Service |
db8df9 |
if (_slot_match(encl->sysfs_path, device->cntrl_path)) {
|
|
Packit Service |
db8df9 |
device->enclosure = encl;
|
|
Packit Service |
db8df9 |
device->encl_index = get_encl_slot(device);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
return (device->enclosure != NULL && device->encl_index != -1);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
int scsi_ses_write(struct block_device *device, enum ibpi_pattern ibpi)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
int ret;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (!device || !device->sysfs_path || !device->enclosure ||
|
|
Packit Service |
db8df9 |
device->encl_index == -1)
|
|
Packit Service |
db8df9 |
__set_errno_and_return(EINVAL);
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/* write only if state has changed */
|
|
Packit Service |
db8df9 |
if (ibpi == device->ibpi_prev)
|
|
Packit Service |
db8df9 |
return 1;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if ((ibpi < IBPI_PATTERN_NORMAL) || (ibpi > SES_REQ_FAULT))
|
|
Packit Service |
db8df9 |
__set_errno_and_return(ERANGE);
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
ret = enclosure_load_pages(device->enclosure);
|
|
Packit Service |
db8df9 |
if (ret) {
|
|
Packit Service |
db8df9 |
log_warning
|
|
Packit Service |
db8df9 |
("Unable to send %s message to %s. Device is missing?",
|
|
Packit Service |
db8df9 |
ibpi2str(ibpi), strstr(device->sysfs_path, "host"));
|
|
Packit Service |
db8df9 |
return ret;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
return ses_write_msg(ibpi, device);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
int scsi_ses_flush(struct block_device *device)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
int ret;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (!device || !device->enclosure)
|
|
Packit Service |
db8df9 |
return 1;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (!device->enclosure->ses_pages)
|
|
Packit Service |
db8df9 |
return 0;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
ret = ses_send_diag(device->enclosure);
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
enclosure_free_pages(device->enclosure);
|
|
Packit Service |
db8df9 |
return ret;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
* @brief Gets a path to slot of sas controller.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* This function returns a sysfs path to component of enclosure the device
|
|
Packit Service |
db8df9 |
* belongs to.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* @param[in] path Canonical sysfs path to block device.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* @return A sysfs path to controller device associated with the given
|
|
Packit Service |
db8df9 |
* block device if successful, otherwise NULL pointer.
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static char *sas_get_slot_path(const char *path, const char *ctrl_path)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
char *host;
|
|
Packit Service |
db8df9 |
char host_path[PATH_MAX] = { 0 };
|
|
Packit Service |
db8df9 |
size_t ctrl_path_len = strlen(ctrl_path);
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (strncmp(path, ctrl_path, ctrl_path_len) != 0)
|
|
Packit Service |
db8df9 |
return NULL;
|
|
Packit Service |
db8df9 |
host = get_path_hostN(path);
|
|
Packit Service |
db8df9 |
if (host) {
|
|
Packit Service |
db8df9 |
snprintf(host_path, sizeof(host_path), "%s/%s/bsg/sas_%s",
|
|
Packit Service |
db8df9 |
ctrl_path, host, host);
|
|
Packit Service |
db8df9 |
free(host);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
return str_dup(host_path);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static char *_get_enc_slot_path(const char *path)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct enclosure_device *device;
|
|
Packit Service |
db8df9 |
char *result = NULL;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
list_for_each(sysfs_get_enclosure_devices(), device) {
|
|
Packit Service |
db8df9 |
result = _slot_find(device->sysfs_path, path);
|
|
Packit Service |
db8df9 |
if (result != NULL)
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
return result;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
char *scsi_get_slot_path(const char *path, const char *ctrl_path)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
char *result = NULL;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
result = _get_enc_slot_path(path);
|
|
Packit Service |
db8df9 |
if (!result)
|
|
Packit Service |
db8df9 |
result = sas_get_slot_path(path, ctrl_path);
|
|
Packit Service |
db8df9 |
return result;
|
|
Packit Service |
db8df9 |
}
|