summaryrefslogtreecommitdiff
path: root/libmultipath/prioritizers/datacore.c
blob: 6b7b202379cec3c606ea504b674ba0065d6409a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/*
 * (C) 2010 Christophe Varoqui
 * (C) 2009 Dembach Goo Infromatik GmbH & Co KG
 * Manon Goo <manon.goo@dg-i.net>
 *
 * datacore.c
 * Version 0.9
 *
 * This program was inspired by work from
 * Matthias Rudolph <matthias.rudolph@hds.com>
 *
 * This work is made available on the basis of the
 * GPLv2 for detials see <http://www.gnu.org/licenses/>.
 *
 * Manon Goo 2009
 *
 *
 */

#include <stdio.h>
#include <sys/ioctl.h>

#include <sys/stat.h>
#include <sg_include.h>
#include <debug.h>
#include <prio.h>

#define INQ_REPLY_LEN 255
#define INQ_CMD_CODE 0x12
#define INQ_CMD_LEN 6

#define dc_log(prio, msg) condlog(prio, "%s: datacore prio: " msg, dev)

int datacore_prio (const char *dev, int sg_fd, char * args)
{
	int k;
	char vendor[8];
	char product[32];
	char luname[32];
	char wwpn[32];
	char sdsname[32];
	unsigned char inqCmdBlk[INQ_CMD_LEN] = { INQ_CMD_CODE, 0, 0, 0, INQ_REPLY_LEN, 0 };
	unsigned char inqBuff[INQ_REPLY_LEN];
	unsigned char *inqBuffp = inqBuff;
	unsigned char sense_buffer[32];
	sg_io_hdr_t io_hdr;

        int timeout = 2000;
	char preferredsds_buff[255] = "";
	char * preferredsds = &preferredsds_buff[0];

	if (!args) {
		dc_log(0, "need prio_args with preferredsds set");
		return 0;
	}

	if (sscanf(args, "timeout=%i preferredsds=%s",
                   &timeout, preferredsds) == 2) {}
	else if (sscanf(args, "preferredsds=%s timeout=%i",
			preferredsds, &timeout) == 2) {}
	else if (sscanf(args, "preferredsds=%s",
			preferredsds) == 1) {}
	else {
		dc_log(0, "unexpected prio_args format");
		return 0;
	}

	// on error just return prio 0
	if (strlen(preferredsds) <= 1) {
		dc_log(0, "prio args: preferredsds too short (1 character min)");
		return 0;
	}
	if ((timeout < 500) || (timeout > 20000)) {
		dc_log(0, "prio args: timeout out of bounds [500:20000]");
		return 0;
	}
	if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000))
		return 0;

	memset (&io_hdr, 0, sizeof (sg_io_hdr_t));
	io_hdr.interface_id = 'S';
	io_hdr.cmd_len = sizeof (inqCmdBlk);
	io_hdr.mx_sb_len = sizeof (sense_buffer);
	io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
	io_hdr.dxfer_len = INQ_REPLY_LEN;
	io_hdr.dxferp = inqBuff;
	io_hdr.cmdp = inqCmdBlk;
	io_hdr.sbp = sense_buffer;
	io_hdr.timeout = timeout;

	// on error just return prio 0
	if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
		return 0;
	if ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK)
		return 0;

	snprintf(vendor, 9, "%.8s\n", inqBuffp + 8);
	snprintf(product, 17, "%.16s", inqBuffp + 16);
	snprintf(luname, 21, "%.19s", inqBuffp + 36);
	snprintf(wwpn, 17, "%.16s", inqBuffp + 96);
	snprintf(sdsname, 17, "%.16s", inqBuffp + 112);

	if (strstr(sdsname , preferredsds))
		return 1;
	return 0;
}

int getprio (struct path * pp, char * args)
{
        return datacore_prio(pp->dev, pp->fd, args);
}