Blame src/smp.c

Packit Service db8df9
/*
Packit Service db8df9
 * Intel(R) Enclosure LED Utilities
Packit Service db8df9
 * Copyright (C) 2011-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
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 <linux/bsg.h>
Packit Service db8df9
#include <scsi/sg.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/ioctl.h>
Packit Service db8df9
#include <sys/stat.h>
Packit Service db8df9
#include <unistd.h>
Packit Service db8df9
#include <sys/sysmacros.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 "block.h"
Packit Service db8df9
#include "cntrl.h"
Packit Service db8df9
#include "config.h"
Packit Service db8df9
#include "enclosure.h"
Packit Service db8df9
#include "ibpi.h"
Packit Service db8df9
#include "list.h"
Packit Service db8df9
#include "scsi.h"
Packit Service db8df9
#include "smp.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
#define GPIO_TX_GP1	0x01
Packit Service db8df9
Packit Service db8df9
#define INIT_IBPI(act, loc, err)  \
Packit Service db8df9
	{	.error = err,     \
Packit Service db8df9
		.locate = loc,    \
Packit Service db8df9
		.activity = act   \
Packit Service db8df9
	}
Packit Service db8df9
Packit Service db8df9
#define LED_OFF	0
Packit Service db8df9
#define LED_ON	1
Packit Service db8df9
#define LED_4HZ	2
Packit Service db8df9
#define LED_I4HZ	3
Packit Service db8df9
#define LED_EOF	4
Packit Service db8df9
#define LED_SOF	5
Packit Service db8df9
#define LED_2HZ	6
Packit Service db8df9
#define LED_I2HZ	7
Packit Service db8df9
Packit Service db8df9
static const struct gpio_rx_table {
Packit Service db8df9
	struct gpio_tx_register_byte pattern;
Packit Service db8df9
	int support_mask;
Packit Service db8df9
} ibpi2sgpio[] = {
Packit Service db8df9
	[IBPI_PATTERN_UNKNOWN]        = { INIT_IBPI(LED_SOF,LED_OFF,LED_OFF), 1 }, /* OK */
Packit Service db8df9
	[IBPI_PATTERN_ONESHOT_NORMAL] = { INIT_IBPI(LED_SOF,LED_OFF,LED_OFF), 1 }, /* OK */
Packit Service db8df9
	[IBPI_PATTERN_NORMAL]         = { INIT_IBPI(LED_SOF,LED_OFF,LED_OFF), 1 }, /* OK */
Packit Service db8df9
	[IBPI_PATTERN_DEGRADED]       = { INIT_IBPI(LED_SOF,LED_OFF,LED_OFF), 0 }, /* NO */
Packit Service db8df9
	[IBPI_PATTERN_REBUILD]        = { INIT_IBPI(LED_SOF,LED_ON,LED_ON), 1 }, /* OK */
Packit Service db8df9
	[IBPI_PATTERN_FAILED_ARRAY]   = { INIT_IBPI(LED_SOF,LED_4HZ,LED_OFF), 0 }, /* NO */
Packit Service db8df9
	[IBPI_PATTERN_HOTSPARE]       = { INIT_IBPI(LED_SOF,LED_OFF,LED_4HZ), 0 }, /* NO */
Packit Service db8df9
	[IBPI_PATTERN_PFA]            = { INIT_IBPI(LED_SOF,LED_OFF,LED_2HZ), 0 }, /* NO */
Packit Service db8df9
	[IBPI_PATTERN_FAILED_DRIVE]   = { INIT_IBPI(LED_SOF,LED_OFF,LED_ON), 1 }, /* OK */
Packit Service db8df9
	[IBPI_PATTERN_LOCATE]         = { INIT_IBPI(LED_SOF,LED_ON,LED_OFF), 1 }, /* OK */
Packit Service db8df9
	[IBPI_PATTERN_LOCATE_OFF]     = { INIT_IBPI(LED_SOF,LED_OFF,LED_OFF), 1 }  /* OK */
Packit Service db8df9
};
Packit Service db8df9
Packit Service db8df9
struct smp_read_response_frame_header {
Packit Service db8df9
	uint8_t frame_type;	/* =0x41 */
Packit Service db8df9
	uint8_t function;	/* =0x02 for read, 0x82 for write */
Packit Service db8df9
	uint8_t function_result;
Packit Service db8df9
	uint8_t reserved;
Packit Service db8df9
	uint32_t read_data[];	/* variable length of data */
Packit Service db8df9
	/* uint32_t crc; */
Packit Service db8df9
} __attribute__ ((__packed__));
Packit Service db8df9
Packit Service db8df9
struct smp_write_response_frame {
Packit Service db8df9
	uint8_t frame_type;	/* =0x41 */
Packit Service db8df9
	uint8_t function;	/* =0x02 for read, 0x82 for write */
Packit Service db8df9
	uint8_t function_result;
Packit Service db8df9
	uint8_t reserved;
Packit Service db8df9
	uint32_t crc;
Packit Service db8df9
} __attribute__ ((__packed__));
Packit Service db8df9
Packit Service db8df9
struct smp_read_request_frame {
Packit Service db8df9
	uint8_t frame_type;	/* =0x40 */
Packit Service db8df9
	uint8_t function;	/* =0x02 for read, 0x82 for write */
Packit Service db8df9
	uint8_t register_type;
Packit Service db8df9
	uint8_t register_index;
Packit Service db8df9
	uint8_t register_count;
Packit Service db8df9
	uint8_t reserved[3];
Packit Service db8df9
	uint32_t crc;
Packit Service db8df9
} __attribute__ ((__packed__));
Packit Service db8df9
Packit Service db8df9
struct smp_write_request_frame_header {
Packit Service db8df9
	uint8_t frame_type;	/* =0x40 */
Packit Service db8df9
	uint8_t function;	/* =0x02 for read, 0x82 for write */
Packit Service db8df9
	uint8_t register_type;
Packit Service db8df9
	uint8_t register_index;
Packit Service db8df9
	uint8_t register_count;
Packit Service db8df9
	uint8_t reserved[3];
Packit Service db8df9
	uint32_t data[];	/* variable length of data */
Packit Service db8df9
	/* uint32_t crc; */
Packit Service db8df9
} __attribute__ ((__packed__));
Packit Service db8df9
Packit Service db8df9
/**
Packit Service db8df9
 * to_sas_gpio_gp_bit - given the gpio frame data find the byte/bit position of 'od'
Packit Service db8df9
 * @od: od bit to find
Packit Service db8df9
 * @data: incoming bitstream (from frame)
Packit Service db8df9
 * @index: requested data register index (from frame)
Packit Service db8df9
 * @count: total number of registers in the bitstream (from frame)
Packit Service db8df9
 * @bit: bit position of 'od' in the returned byte
Packit Service db8df9
 *
Packit Service db8df9
 * returns NULL if 'od' is not in 'data'
Packit Service db8df9
 *
Packit Service db8df9
 * From SFF-8485 v0.7:
Packit Service db8df9
 * "In GPIO_TX[1], bit 0 of byte 3 contains the first bit (i.e., OD0.0)
Packit Service db8df9
 *  and bit 7 of byte 0 contains the 32nd bit (i.e., OD10.1).
Packit Service db8df9
 *
Packit Service db8df9
 *  In GPIO_TX[2], bit 0 of byte 3 contains the 33rd bit (i.e., OD10.2)
Packit Service db8df9
 *  and bit 7 of byte 0 contains the 64th bit (i.e., OD21.0)."
Packit Service db8df9
 *
Packit Service db8df9
 * The general-purpose (raw-bitstream) RX registers have the same layout
Packit Service db8df9
 * although 'od' is renamed 'id' for 'input data'.
Packit Service db8df9
 *
Packit Service db8df9
 * SFF-8489 defines the behavior of the LEDs in response to the 'od' values.
Packit Service db8df9
 */
Packit Service db8df9
static unsigned char *to_sas_gpio_gp_bit(unsigned int od, unsigned char *data,
Packit Service db8df9
					 unsigned char index,
Packit Service db8df9
					 unsigned char count,
Packit Service db8df9
					 unsigned char *bit)
Packit Service db8df9
{
Packit Service db8df9
	unsigned int reg;
Packit Service db8df9
	unsigned char byte;
Packit Service db8df9
Packit Service db8df9
	/* gp registers start at index 1 */
Packit Service db8df9
	if (index == 0)
Packit Service db8df9
		return NULL;
Packit Service db8df9
Packit Service db8df9
	index--;		/* make index 0-based */
Packit Service db8df9
	if (od < index * 32)
Packit Service db8df9
		return NULL;
Packit Service db8df9
Packit Service db8df9
	od -= index * 32;
Packit Service db8df9
	reg = od >> 5;
Packit Service db8df9
Packit Service db8df9
	if (reg >= count)
Packit Service db8df9
		return NULL;
Packit Service db8df9
Packit Service db8df9
	od &= (1 << 5) - 1;
Packit Service db8df9
	byte = 3 - (od >> 3);
Packit Service db8df9
	*bit = od & ((1 << 3) - 1);
Packit Service db8df9
Packit Service db8df9
	return &data[reg * 4 + byte];
Packit Service db8df9
}
Packit Service db8df9
Packit Service db8df9
int try_test_sas_gpio_gp_bit(unsigned int od, unsigned char *data,
Packit Service db8df9
			     unsigned char index, unsigned char count)
Packit Service db8df9
{
Packit Service db8df9
	unsigned char *byte;
Packit Service db8df9
	unsigned char bit;
Packit Service db8df9
Packit Service db8df9
	byte = to_sas_gpio_gp_bit(od, data, index, count, &bit;;
Packit Service db8df9
	if (!byte)
Packit Service db8df9
		return -1;
Packit Service db8df9
Packit Service db8df9
	return (*byte >> bit) & 1;
Packit Service db8df9
}
Packit Service db8df9
Packit Service db8df9
int try_set_sas_gpio_gp_bit(unsigned int od, unsigned char *data,
Packit Service db8df9
			    unsigned char index, unsigned char count)
Packit Service db8df9
{
Packit Service db8df9
	unsigned char *byte;
Packit Service db8df9
	unsigned char bit;
Packit Service db8df9
Packit Service db8df9
	byte = to_sas_gpio_gp_bit(od, data, index, count, &bit;;
Packit Service db8df9
	if (!byte)
Packit Service db8df9
		return 0;
Packit Service db8df9
Packit Service db8df9
	*byte |= 1 << bit;
Packit Service db8df9
	return 1;
Packit Service db8df9
}
Packit Service db8df9
Packit Service db8df9
int try_clear_sas_gpio_gp_bit(unsigned int od, unsigned char *data,
Packit Service db8df9
			      unsigned char index, unsigned char count)
Packit Service db8df9
{
Packit Service db8df9
	unsigned char *byte;
Packit Service db8df9
	unsigned char bit;
Packit Service db8df9
Packit Service db8df9
	byte = to_sas_gpio_gp_bit(od, data, index, count, &bit;;
Packit Service db8df9
	if (!byte)
Packit Service db8df9
		return 0;
Packit Service db8df9
Packit Service db8df9
	*byte &= ~(1 << bit);
Packit Service db8df9
	return 1;
Packit Service db8df9
}
Packit Service db8df9
Packit Service db8df9
/**
Packit Service db8df9
 * set_raw_pattern - turn a tx register into a tx_gp bitstream
Packit Service db8df9
 *
Packit Service db8df9
 * takes @dev_idx (phy index) and a @pattern (error, locate, activity)
Packit Service db8df9
 * tuple and modifies the bitstream in @data accordingly */
Packit Service db8df9
int set_raw_pattern(unsigned int dev_idx, unsigned char *data,
Packit Service db8df9
		    const struct gpio_tx_register_byte *pattern)
Packit Service db8df9
{
Packit Service db8df9
	int od_offset = dev_idx * 3;
Packit Service db8df9
	int rc = 0;
Packit Service db8df9
Packit Service db8df9
	if (pattern->activity == LED_ON)
Packit Service db8df9
		rc +=
Packit Service db8df9
		    try_set_sas_gpio_gp_bit(od_offset + 0, data, GPIO_TX_GP1,
Packit Service db8df9
					    1);
Packit Service db8df9
	else
Packit Service db8df9
		rc +=
Packit Service db8df9
		    try_clear_sas_gpio_gp_bit(od_offset + 0, data, GPIO_TX_GP1,
Packit Service db8df9
					      1);
Packit Service db8df9
Packit Service db8df9
	if (pattern->locate == LED_ON)
Packit Service db8df9
		rc +=
Packit Service db8df9
		    try_set_sas_gpio_gp_bit(od_offset + 1, data, GPIO_TX_GP1,
Packit Service db8df9
					    1);
Packit Service db8df9
	else
Packit Service db8df9
		rc +=
Packit Service db8df9
		    try_clear_sas_gpio_gp_bit(od_offset + 1, data, GPIO_TX_GP1,
Packit Service db8df9
					      1);
Packit Service db8df9
Packit Service db8df9
	if (pattern->error == LED_ON)
Packit Service db8df9
		rc +=
Packit Service db8df9
		    try_set_sas_gpio_gp_bit(od_offset + 2, data, GPIO_TX_GP1,
Packit Service db8df9
					    1);
Packit Service db8df9
	else
Packit Service db8df9
		rc +=
Packit Service db8df9
		    try_clear_sas_gpio_gp_bit(od_offset + 2, data, GPIO_TX_GP1,
Packit Service db8df9
					      1);
Packit Service db8df9
Packit Service db8df9
	return rc == 3;
Packit Service db8df9
}
Packit Service db8df9
Packit Service db8df9
/**
Packit Service db8df9
 * @brief open device for smp protocol
Packit Service db8df9
 */
Packit Service db8df9
static int _open_smp_device(const char *filename)
Packit Service db8df9
{
Packit Service db8df9
	char buf[PATH_MAX];
Packit Service db8df9
	FILE *df;
Packit Service db8df9
	int hba_fd;
Packit Service db8df9
	int dmaj, dmin;
Packit Service db8df9
	snprintf(buf, sizeof(buf), "%s/dev", filename);
Packit Service db8df9
	df = fopen(buf, "r");
Packit Service db8df9
	if (!df)
Packit Service db8df9
		return -1;
Packit Service db8df9
	if (fgets(buf, sizeof(buf), df) == NULL) {
Packit Service db8df9
		fclose(df);
Packit Service db8df9
		return -1;
Packit Service db8df9
	}
Packit Service db8df9
	if (sscanf(buf, "%d:%d", &dmaj, &dmin) != 2) {
Packit Service db8df9
		fclose(df);
Packit Service db8df9
		return -1;
Packit Service db8df9
	}
Packit Service db8df9
	fclose(df);
Packit Service db8df9
	snprintf(buf, sizeof(buf), "/var/tmp/led.%d.%d.%d", dmaj, dmin,
Packit Service db8df9
		 getpid());
Packit Service db8df9
	if (mknod(buf, S_IFCHR | S_IRUSR | S_IWUSR, makedev(dmaj, dmin)) < 0)
Packit Service db8df9
		return -1;
Packit Service db8df9
	hba_fd = open(buf, O_RDWR);
Packit Service db8df9
	unlink(buf);
Packit Service db8df9
	if (hba_fd < 0)
Packit Service db8df9
		return -1;
Packit Service db8df9
	return hba_fd;
Packit Service db8df9
}
Packit Service db8df9
Packit Service db8df9
/**
Packit Service db8df9
 * @brief close smp device
Packit Service db8df9
 */
Packit Service db8df9
static int _close_smp_device(int fd)
Packit Service db8df9
{
Packit Service db8df9
	return close(fd);
Packit Service db8df9
}
Packit Service db8df9
Packit Service db8df9
/**
Packit Service db8df9
   @brief use sg protocol in order to send data directly to hba driver
Packit Service db8df9
 */
Packit Service db8df9
static int _send_smp_frame(int hba, void *data, size_t data_size,
Packit Service db8df9
			   void *response, size_t *response_size)
Packit Service db8df9
{
Packit Service db8df9
	struct sg_io_v4 sg_frame;
Packit Service db8df9
	uint8_t request_buf[SCSI_MAX_CDB_LENGTH];
Packit Service db8df9
	int response_status = 0;
Packit Service db8df9
Packit Service db8df9
	/* wrap the frame into sg structure */
Packit Service db8df9
	memset(&sg_frame, 0, sizeof(sg_frame));
Packit Service db8df9
	sg_frame.guard = 'Q';
Packit Service db8df9
	sg_frame.protocol = BSG_PROTOCOL_SCSI;
Packit Service db8df9
	sg_frame.subprotocol = BSG_SUB_PROTOCOL_SCSI_TRANSPORT;
Packit Service db8df9
Packit Service db8df9
	sg_frame.request_len = sizeof(request_buf);
Packit Service db8df9
	sg_frame.request = (uintptr_t) request_buf;
Packit Service db8df9
Packit Service db8df9
	sg_frame.dout_xfer_len = data_size;
Packit Service db8df9
	sg_frame.dout_xferp = (uintptr_t) data;
Packit Service db8df9
Packit Service db8df9
	sg_frame.din_xfer_len = *response_size;
Packit Service db8df9
	sg_frame.din_xferp = (uintptr_t) response;
Packit Service db8df9
Packit Service db8df9
	sg_frame.timeout = SG_RESPONSE_TIMEOUT;
Packit Service db8df9
	/* send ioctl */
Packit Service db8df9
	if (ioctl(hba, SG_IO, &sg_frame) < 0)
Packit Service db8df9
		return -1;
Packit Service db8df9
Packit Service db8df9
	/* return status */
Packit Service db8df9
	if (sg_frame.driver_status)
Packit Service db8df9
		response_status = sg_frame.driver_status;
Packit Service db8df9
	else if (sg_frame.transport_status)
Packit Service db8df9
		response_status = sg_frame.transport_status;
Packit Service db8df9
	else if (sg_frame.device_status)
Packit Service db8df9
		response_status = sg_frame.device_status;
Packit Service db8df9
Packit Service db8df9
	*response_size = sg_frame.din_xfer_len - sg_frame.din_resid;
Packit Service db8df9
Packit Service db8df9
	return response_status;
Packit Service db8df9
}
Packit Service db8df9
Packit Service db8df9
/* 1024 bytes for data, 4 for crc */
Packit Service db8df9
#define MAX_SMP_FRAME_DATA 1024
Packit Service db8df9
#define MAX_SMP_FRAME_LEN (sizeof(struct smp_write_request_frame_header) + \
Packit Service db8df9
				MAX_SMP_FRAME_DATA + SMP_FRAME_CRC_LEN)
Packit Service db8df9
Packit Service db8df9
/**
Packit Service db8df9
   @brief prepare full smp frame ready to send to hba
Packit Service db8df9
Packit Service db8df9
   @note len is a number of 32bit words
Packit Service db8df9
 */
Packit Service db8df9
static int _start_smp_write_gpio(int hba,
Packit Service db8df9
				 struct smp_write_request_frame_header *header,
Packit Service db8df9
				 void *data, size_t len)
Packit Service db8df9
{
Packit Service db8df9
	uint8_t buf[MAX_SMP_FRAME_LEN];
Packit Service db8df9
	struct smp_write_response_frame response;
Packit Service db8df9
	size_t response_size = sizeof(response);
Packit Service db8df9
	int status;
Packit Service db8df9
Packit Service db8df9
	memset(&response, 0, sizeof(response));
Packit Service db8df9
	/* create full frame */
Packit Service db8df9
	if (len * SMP_DATA_CHUNK_SIZE > MAX_SMP_FRAME_DATA)
Packit Service db8df9
		__set_errno_and_return(EINVAL);
Packit Service db8df9
	memset(buf, 0, sizeof(buf));
Packit Service db8df9
	memcpy(buf, header, sizeof(*header));
Packit Service db8df9
	memcpy(buf + sizeof(*header), data, len * SMP_DATA_CHUNK_SIZE);
Packit Service db8df9
Packit Service db8df9
	status =
Packit Service db8df9
	    _send_smp_frame(hba, buf,
Packit Service db8df9
			    sizeof(*header) + len * SMP_DATA_CHUNK_SIZE +
Packit Service db8df9
			    SMP_FRAME_CRC_LEN, &response, &response_size);
Packit Service db8df9
Packit Service db8df9
	/* if frame is somehow malformed return failure */
Packit Service db8df9
	if (status != GPIO_STATUS_OK ||
Packit Service db8df9
	    response.frame_type != SMP_FRAME_TYPE_RESP ||
Packit Service db8df9
	    response.function != header->function) {
Packit Service db8df9
		return GPIO_STATUS_FAILURE;
Packit Service db8df9
	}
Packit Service db8df9
Packit Service db8df9
	return response.function_result;
Packit Service db8df9
}
Packit Service db8df9
Packit Service db8df9
/**
Packit Service db8df9
   @brief prepare smp frame header
Packit Service db8df9
 */
Packit Service db8df9
int smp_write_gpio(const char *path, int smp_reg_type,
Packit Service db8df9
			   int smp_reg_index, int smp_reg_count, void *data,
Packit Service db8df9
			   size_t len)
Packit Service db8df9
{
Packit Service db8df9
	struct smp_write_request_frame_header header;
Packit Service db8df9
	int status;
Packit Service db8df9
	header.frame_type = SMP_FRAME_TYPE_REQ;
Packit Service db8df9
	header.function = SMP_FUNC_GPIO_WRITE;
Packit Service db8df9
	header.register_type = smp_reg_type;
Packit Service db8df9
	header.register_index = smp_reg_index;
Packit Service db8df9
	header.register_count = smp_reg_count;
Packit Service db8df9
	memset(header.reserved, 0, sizeof(header.reserved));
Packit Service db8df9
	int fd = _open_smp_device(path);
Packit Service db8df9
	status = _start_smp_write_gpio(fd, &header, data, len);
Packit Service db8df9
	_close_smp_device(fd);
Packit Service db8df9
	return status;
Packit Service db8df9
}
Packit Service db8df9
Packit Service db8df9
#define BLINK_GEN_1HZ				8
Packit Service db8df9
#define BLINK_GEN_2HZ				4
Packit Service db8df9
#define BLINK_GEN_4HZ				2
Packit Service db8df9
#define DEFAULT_FORCED_ACTIVITY_OFF		1
Packit Service db8df9
#define DEFAULT_MAXIMUM_ACTIVITY_ON		2
Packit Service db8df9
#define DEFAULT_STRETCH_ACTIVITY_OFF		0
Packit Service db8df9
#define DEFAULT_STRETCH_ACTIVITY_ON		0
Packit Service db8df9
Packit Service db8df9
/* one data chunk is 32bit long */
Packit Service db8df9
#define SMP_DATA_CHUNKS				1
Packit Service db8df9
Packit Service db8df9
struct gpio_tx_register_byte *get_bdev_ibpi_buffer(struct block_device *bdevice)
Packit Service db8df9
{
Packit Service db8df9
	if (bdevice && bdevice->host)
Packit Service db8df9
		return bdevice->host->ibpi_state_buffer;
Packit Service db8df9
	return NULL;
Packit Service db8df9
}
Packit Service db8df9
Packit Service db8df9
/**
Packit Service db8df9
 */
Packit Service db8df9
int scsi_smp_fill_buffer(struct block_device *device, enum ibpi_pattern ibpi)
Packit Service db8df9
{
Packit Service db8df9
	const char *sysfs_path = device->cntrl_path;
Packit Service db8df9
	struct gpio_tx_register_byte *gpio_tx;
Packit Service db8df9
Packit Service db8df9
	if (sysfs_path == NULL)
Packit Service db8df9
		__set_errno_and_return(EINVAL);
Packit Service db8df9
	if ((ibpi < IBPI_PATTERN_NORMAL) || (ibpi > IBPI_PATTERN_LOCATE_OFF))
Packit Service db8df9
		__set_errno_and_return(ERANGE);
Packit Service db8df9
	if (!device->cntrl) {
Packit Service db8df9
		log_debug("No ctrl dev for '%s'", strstr(sysfs_path, "host"));
Packit Service db8df9
		__set_errno_and_return(ENODEV);
Packit Service db8df9
	}
Packit Service db8df9
	if (device->cntrl->cntrl_type != CNTRL_TYPE_SCSI) {
Packit Service db8df9
		log_debug("No SCSI ctrl dev '%s'", strstr(sysfs_path, "host"));
Packit Service db8df9
		__set_errno_and_return(EINVAL);
Packit Service db8df9
	}
Packit Service db8df9
	if (!device->host) {
Packit Service db8df9
		log_debug("No host for '%s'", strstr(sysfs_path, "host"));
Packit Service db8df9
		__set_errno_and_return(ENODEV);
Packit Service db8df9
	}
Packit Service db8df9
Packit Service db8df9
	if (device->cntrl->isci_present && !ibpi2sgpio[ibpi].support_mask) {
Packit Service db8df9
		char *c = strrchr(device->sysfs_path, '/');
Packit Service db8df9
		if (c++) {
Packit Service db8df9
			log_debug
Packit Service db8df9
			    ("pattern %s not supported for device (/dev/%s)",
Packit Service db8df9
			     ibpi2str(ibpi), c);
Packit Service db8df9
			fprintf(stderr,
Packit Service db8df9
				"%s(): pattern %s not supported for device (/dev/%s)\n",
Packit Service db8df9
				__func__, ibpi2str(ibpi), c);
Packit Service db8df9
		} else {
Packit Service db8df9
			log_debug("pattern %s not supported for device %s",
Packit Service db8df9
				  ibpi2str(ibpi), device->sysfs_path);
Packit Service db8df9
			fprintf(stderr,
Packit Service db8df9
				"%s(): pattern %s not supported for device\n\t(%s)\n",
Packit Service db8df9
				__func__, ibpi2str(ibpi), device->sysfs_path);
Packit Service db8df9
		}
Packit Service db8df9
		__set_errno_and_return(ENOTSUP);
Packit Service db8df9
	}
Packit Service db8df9
Packit Service db8df9
	gpio_tx = get_bdev_ibpi_buffer(device);
Packit Service db8df9
	if (!gpio_tx) {
Packit Service db8df9
		log_debug("%s(): no IBPI buffer. Skipping.", __func__);
Packit Service db8df9
		__set_errno_and_return(ENODEV);
Packit Service db8df9
	}
Packit Service db8df9
Packit Service db8df9
	if (device->cntrl->isci_present) {
Packit Service db8df9
		/* update bit stream for this device */
Packit Service db8df9
		set_raw_pattern(device->phy_index,
Packit Service db8df9
			&device->host->bitstream[0], &ibpi2sgpio[ibpi].pattern);
Packit Service db8df9
	} else {
Packit Service db8df9
		/*
Packit Service db8df9
		 * GPIO_TX[n] register has the highest numbered drive of the
Packit Service db8df9
		 * four in the first byte and the lowest numbered drive in the
Packit Service db8df9
		 * fourth byte. See SFF-8485 Rev. 0.7 Table 24.
Packit Service db8df9
		 */
Packit Service db8df9
		gpio_tx[device->phy_index + 3 - (device->phy_index % 4) * 2] =
Packit Service db8df9
			ibpi2sgpio[ibpi].pattern;
Packit Service db8df9
	}
Packit Service db8df9
Packit Service db8df9
	/* write only if state has changed */
Packit Service db8df9
	if (ibpi != device->ibpi_prev)
Packit Service db8df9
		device->host->flush = 1;
Packit Service db8df9
Packit Service db8df9
	return 1;
Packit Service db8df9
}
Packit Service db8df9
Packit Service db8df9
int scsi_smp_write_buffer(struct block_device *device)
Packit Service db8df9
{
Packit Service db8df9
	const char *sysfs_path = device->cntrl_path;
Packit Service db8df9
Packit Service db8df9
	if (sysfs_path == NULL)
Packit Service db8df9
		__set_errno_and_return(EINVAL);
Packit Service db8df9
	if (!device->host)
Packit Service db8df9
		__set_errno_and_return(ENODEV);
Packit Service db8df9
Packit Service db8df9
	if (device->host->flush) {
Packit Service db8df9
		device->host->flush = 0;
Packit Service db8df9
		/* re-transmit the bitstream */
Packit Service db8df9
		if (device->cntrl->isci_present) {
Packit Service db8df9
			return smp_write_gpio(sysfs_path,
Packit Service db8df9
					       GPIO_REG_TYPE_TX_GP,
Packit Service db8df9
					       GPIO_TX_GP1, 1,
Packit Service db8df9
					       &device->host->bitstream[0],
Packit Service db8df9
					       SMP_DATA_CHUNKS);
Packit Service db8df9
		} else {
Packit Service db8df9
			return smp_write_gpio(sysfs_path,
Packit Service db8df9
					       GPIO_REG_TYPE_TX,
Packit Service db8df9
					       0, (device->host->ports+3)/4,
Packit Service db8df9
					       device->host->ibpi_state_buffer,
Packit Service db8df9
					       (device->host->ports+3)/4);
Packit Service db8df9
		}
Packit Service db8df9
	} else
Packit Service db8df9
		return 1;
Packit Service db8df9
}
Packit Service db8df9
Packit Service db8df9
/**
Packit Service db8df9
 */
Packit Service db8df9
static void init_smp(struct cntrl_device *device)
Packit Service db8df9
{
Packit Service db8df9
	struct _host_type *hosts;
Packit Service db8df9
	int i;
Packit Service db8df9
	if (!device)
Packit Service db8df9
		return;
Packit Service db8df9
Packit Service db8df9
	for (hosts = device->hosts; hosts; hosts = hosts->next) {
Packit Service db8df9
		/* already initialized */
Packit Service db8df9
		if (hosts->ibpi_state_buffer)
Packit Service db8df9
			continue;
Packit Service db8df9
		hosts->ibpi_state_buffer =
Packit Service db8df9
				calloc(hosts->ports,
Packit Service db8df9
					sizeof(struct
Packit Service db8df9
					gpio_tx_register_byte));
Packit Service db8df9
Packit Service db8df9
		if (!hosts->ibpi_state_buffer)
Packit Service db8df9
			continue;
Packit Service db8df9
Packit Service db8df9
		for (i = 0; i < hosts->ports; i++)
Packit Service db8df9
			set_raw_pattern(i, &hosts->bitstream[0],
Packit Service db8df9
					&ibpi2sgpio
Packit Service db8df9
					[IBPI_PATTERN_ONESHOT_NORMAL].pattern);
Packit Service db8df9
		hosts->flush = 0;
Packit Service db8df9
	}
Packit Service db8df9
}
Packit Service db8df9
Packit Service db8df9
/**
Packit Service db8df9
 */
Packit Service db8df9
int cntrl_init_smp(const char *path, struct cntrl_device *cntrl)
Packit Service db8df9
{
Packit Service db8df9
	char *path2 = NULL;
Packit Service db8df9
	char *c;
Packit Service db8df9
	int host, port = 0;
Packit Service db8df9
	struct dirent *de;
Packit Service db8df9
	DIR *d;
Packit Service db8df9
Packit Service db8df9
	if (!cntrl)
Packit Service db8df9
		return port;
Packit Service db8df9
Packit Service db8df9
	/* Other case - just init controller. */
Packit Service db8df9
	if (path && strstr(path, "port-")) {
Packit Service db8df9
		path2 = str_dup(path);
Packit Service db8df9
		if (!path2)
Packit Service db8df9
			return port;
Packit Service db8df9
Packit Service db8df9
		c = strstr(path2, "port-");
Packit Service db8df9
		if (!c) {
Packit Service db8df9
			/* Should not happen. */
Packit Service db8df9
			log_debug("%s() missing 'port' in path '%s'", __func__,
Packit Service db8df9
				  path2);
Packit Service db8df9
			free(path2);
Packit Service db8df9
			return port;
Packit Service db8df9
		}
Packit Service db8df9
		c = strchr(c, '/');
Packit Service db8df9
		if (!c) {
Packit Service db8df9
			free(path2);
Packit Service db8df9
			return port;
Packit Service db8df9
		}
Packit Service db8df9
		*c = 0;
Packit Service db8df9
		/* And now path2 has only up to 'port-...' string. */
Packit Service db8df9
Packit Service db8df9
		/* this should open port-XX:X directory
Packit Service db8df9
		 * FIXME: for enclosure it may be port-XX:Y:Z but it's a second
Packit Service db8df9
		 * occurrence
Packit Service db8df9
		 *
Packit Service db8df9
		 * We may try this on the missing device.
Packit Service db8df9
		 * */
Packit Service db8df9
		d = opendir(path2);
Packit Service db8df9
		if (!d) {
Packit Service db8df9
			log_debug("%s() Error dir open '%s', path ='%s'",
Packit Service db8df9
				  __func__, path2, path);
Packit Service db8df9
			free(path2);
Packit Service db8df9
			return port;
Packit Service db8df9
		}
Packit Service db8df9
		while ((de = readdir(d))) {
Packit Service db8df9
			if ((strcmp(de->d_name, ".") == 0) ||
Packit Service db8df9
			    (strcmp(de->d_name, "..")) == 0) {
Packit Service db8df9
				continue;
Packit Service db8df9
			}
Packit Service db8df9
			if (strncmp(de->d_name, "phy-", strlen("phy-")) == 0) {
Packit Service db8df9
				/* Need link called "phy-XX:Y
Packit Service db8df9
				 * Y is real phy we need.
Packit Service db8df9
				 * This can also be found
Packit Service db8df9
				 * in phy_identifier file */
Packit Service db8df9
				if (sscanf(de->d_name, "phy-%d:%d", &host, &port) != 2)
Packit Service db8df9
					continue;
Packit Service db8df9
Packit Service db8df9
				break;
Packit Service db8df9
			}
Packit Service db8df9
		}
Packit Service db8df9
		closedir(d);
Packit Service db8df9
		free(path2);
Packit Service db8df9
	}
Packit Service db8df9
	init_smp(cntrl);
Packit Service db8df9
	return port;
Packit Service db8df9
}