chiark / gitweb /
21890621e05654888821f44a7fda0bdf051ffeca
[elogind.git] / extras / multipath-tools / 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[MX_ALLOC_LEN + 1];
165                                                                                                                  
166         if ((fd = open(devname, O_RDONLY)) < 0)
167                         return 0;
168
169         if (0 == do_inq(fd, 0, 1, 0x83, buff, MX_ALLOC_LEN, 1)) {
170                 sprint_wwid(wwid, &buff[8]);
171                 close(fd);
172                 return 1; /* success */
173         }
174
175         close(fd);
176         return 0; /* not good */
177 }
178
179 long
180 get_disk_size (char * devname) {
181         long size;
182         int fd;
183         char attr_path[FILE_NAME_SIZE];
184         char sysfs_path[FILE_NAME_SIZE];
185         char buff[FILE_NAME_SIZE];
186         char basedev[FILE_NAME_SIZE];
187                                                                                                                  
188         if (0 == sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
189                 basename(devname, basedev);
190                 sprintf(attr_path, "%s/block/%s/size",
191                         sysfs_path, basedev);
192                 if (0 > sysfs_read_attribute_value(attr_path, buff,
193                                          FILE_NAME_SIZE * sizeof(char)))
194                         return -1;
195                 size = atoi(buff);
196                 return size;
197         } else {
198                 if ((fd = open(devname, O_RDONLY)) < 0)
199                         return -1;
200                 if(!ioctl(fd, BLKGETSIZE, &size))
201                         return size;
202         }
203         return -1;
204 }
205
206 int
207 do_tur(char *dev)
208 {
209         unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
210         struct sg_io_hdr io_hdr;
211         unsigned char sense_buffer[32];
212         int fd;
213
214         fd = open(dev, O_RDONLY);
215         
216         if (fd < 0)
217                 return 0;
218
219         memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
220         io_hdr.interface_id = 'S';
221         io_hdr.cmd_len = sizeof (turCmdBlk);
222         io_hdr.mx_sb_len = sizeof (sense_buffer);
223         io_hdr.dxfer_direction = SG_DXFER_NONE;
224         io_hdr.cmdp = turCmdBlk;
225         io_hdr.sbp = sense_buffer;
226         io_hdr.timeout = 20000;
227         io_hdr.pack_id = 0;
228
229         if (ioctl(fd, SG_IO, &io_hdr) < 0) {
230                 close(fd);
231                 return 0;
232         }
233
234         close(fd);
235         
236         if (io_hdr.info & SG_INFO_OK_MASK)
237                 return 0;
238
239         return 1;
240 }