chiark / gitweb /
[PATCH] multipath update
[elogind.git] / extras / multipath / devinfo.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <fcntl.h>
5 #include <sys/ioctl.h>
6 #include <sysfs/libsysfs.h>
7 #include "devinfo.h"
8 #include "sg_include.h"
9
10 #define FILE_NAME_SIZE 255
11
12 void
13 basename(char * str1, char * str2)
14 {
15         char *p = str1 + (strlen(str1) - 1);
16  
17         while (*--p != '/')
18                 continue;
19         strcpy(str2, ++p);
20 }
21
22 static int
23 do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
24        void *resp, int mx_resp_len, int noisy)
25 {
26         unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
27             { INQUIRY_CMD, 0, 0, 0, 0, 0 };
28         unsigned char sense_b[SENSE_BUFF_LEN];
29         struct sg_io_hdr io_hdr;
30                                                                                                                  
31         if (cmddt)
32                 inqCmdBlk[1] |= 2;
33         if (evpd)
34                 inqCmdBlk[1] |= 1;
35         inqCmdBlk[2] = (unsigned char) pg_op;
36         inqCmdBlk[4] = (unsigned char) mx_resp_len;
37         memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
38         io_hdr.interface_id = 'S';
39         io_hdr.cmd_len = sizeof (inqCmdBlk);
40         io_hdr.mx_sb_len = sizeof (sense_b);
41         io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
42         io_hdr.dxfer_len = mx_resp_len;
43         io_hdr.dxferp = resp;
44         io_hdr.cmdp = inqCmdBlk;
45         io_hdr.sbp = sense_b;
46         io_hdr.timeout = DEF_TIMEOUT;
47  
48         if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
49                 perror("SG_IO (inquiry) error");
50                 return -1;
51         }
52  
53         /* treat SG_ERR here to get rid of sg_err.[ch] */
54         io_hdr.status &= 0x7e;
55         if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
56             (0 == io_hdr.driver_status))
57                 return 0;
58         if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
59             (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
60             (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
61                 if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
62                         int sense_key;
63                         unsigned char * sense_buffer = io_hdr.sbp;
64                         if (sense_buffer[0] & 0x2)
65                                 sense_key = sense_buffer[1] & 0xf;
66                         else
67                                 sense_key = sense_buffer[2] & 0xf;
68                         if(RECOVERED_ERROR == sense_key)
69                                 return 0;
70                 }
71         }
72         return -1;
73 }
74
75 int
76 get_serial (char * str, char * devname)
77 {
78         int fd;
79         int len;
80         char buff[MX_ALLOC_LEN + 1];
81
82         if ((fd = open(devname, O_RDONLY)) < 0)
83                 return 0;
84
85         if (0 == do_inq(fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) {
86                 len = buff[3];
87                 if (len > 0) {
88                         memcpy(str, buff + 4, len);
89                         buff[len] = '\0';
90                 }
91                 close(fd);
92                 return 1;
93         }
94         close(fd);
95         return 0;
96 }
97
98 int
99 get_lun_strings(char * vendor_id, char * product_id, char * rev, char * devname)
100 {
101         int fd;
102         char buff[36];
103         char attr_path[FILE_NAME_SIZE];
104         char sysfs_path[FILE_NAME_SIZE];
105         char basedev[FILE_NAME_SIZE];
106                                                                                                                  
107         if (0 == sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
108                 /* sysfs style */
109                 basename(devname, basedev);
110  
111                 sprintf(attr_path, "%s/block/%s/device/vendor",
112                         sysfs_path, basedev);
113                 if (0 > sysfs_read_attribute_value(attr_path,
114                     vendor_id, 8)) return 0;
115  
116                 sprintf(attr_path, "%s/block/%s/device/model",
117                         sysfs_path, basedev);
118                 if (0 > sysfs_read_attribute_value(attr_path,
119                     product_id, 16)) return 0;
120  
121                 sprintf(attr_path, "%s/block/%s/device/rev",
122                         sysfs_path, basedev);
123                 if (0 > sysfs_read_attribute_value(attr_path,
124                     rev, 4)) return 0;
125         } else {
126                 /* ioctl style */
127                 if ((fd = open(devname, O_RDONLY)) < 0)
128                         return 0;
129                 if (0 != do_inq(fd, 0, 0, 0, buff, 36, 1))
130                         return 0;
131                 memcpy(vendor_id, &buff[8], 8);
132                 memcpy(product_id, &buff[16], 16);
133                 memcpy(rev, &buff[32], 4);
134                 close(fd);
135                 return 1;
136         }
137         return 0;
138 }
139
140 static void
141 sprint_wwid(char * buff, const char * str)
142 {
143         int i;
144         const char *p;
145         char *cursor;
146         unsigned char c;
147                                                                                                                  
148         p = str;
149         cursor = buff;
150         for (i = 0; i <= WWID_SIZE / 2 - 1; i++) {
151                 c = *p++;
152                 sprintf(cursor, "%.2x", (int) (unsigned char) c);
153                 cursor += 2;
154         }
155         buff[WWID_SIZE - 1] = '\0';
156 }
157                                                                                                                  
158 /* get EVPD page 0x83 off 8 */
159 /* tested ok with StorageWorks */
160 int
161 get_evpd_wwid(char * devname, char * wwid)
162 {
163         int fd;
164         char buff[64];
165                                                                                                                  
166         if ((fd = open(devname, O_RDONLY)) < 0)
167                         return 0;
168                                                                                                                  
169         if (0 == do_inq(fd, 0, 1, 0x83, buff, sizeof (buff), 1)) {
170                 sprint_wwid(wwid, &buff[8]);
171                 close(fd);
172                 return 1; /* success */
173         }
174         close(fd);
175         return 0; /* not good */
176 }
177
178 long
179 get_disk_size (char * devname) {
180         long size;
181         int fd;
182         char attr_path[FILE_NAME_SIZE];
183         char sysfs_path[FILE_NAME_SIZE];
184         char buff[FILE_NAME_SIZE];
185         char basedev[FILE_NAME_SIZE];
186                                                                                                                  
187         if (0 == sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
188                 basename(devname, basedev);
189                 sprintf(attr_path, "%s/block/%s/size",
190                         sysfs_path, basedev);
191                 if (0 > sysfs_read_attribute_value(attr_path, buff,
192                                          FILE_NAME_SIZE * sizeof(char)))
193                         return -1;
194                 size = atoi(buff);
195                 return size;
196         } else {
197                 if ((fd = open(devname, O_RDONLY)) < 0)
198                         return -1;
199                 if(!ioctl(fd, BLKGETSIZE, &size))
200                         return size;
201         }
202         return -1;
203 }
204