[build] minor compilation issues
[platform/upstream/multipath-tools.git] / libmultipath / discovery.c
1 /*
2  * Copyright (c) 2004, 2005, 2006 Christophe Varoqui
3  * Copyright (c) 2005 Stefan Bader, IBM
4  * Copyright (c) 2005 Mike Anderson
5  */
6 #include <stdio.h>
7 #include <unistd.h>
8 #include <fcntl.h>
9 #include <sys/ioctl.h>
10 #include <sys/stat.h>
11 #include <errno.h>
12 #include <sysfs/dlist.h>
13 #include <sysfs/libsysfs.h>
14
15 #include <checkers.h>
16
17 #include "vector.h"
18 #include "memory.h"
19 #include "util.h"
20 #include "structs.h"
21 #include "config.h"
22 #include "blacklist.h"
23 #include "callout.h"
24 #include "debug.h"
25 #include "propsel.h"
26 #include "sg_include.h"
27 #include "discovery.h"
28
29 struct path *
30 store_pathinfo (vector pathvec, vector hwtable, char * devname, int flag)
31 {
32         struct path * pp;
33
34         pp = alloc_path();
35
36         if (!pp)
37                 return NULL;
38
39         if(safe_sprintf(pp->dev, "%s", devname)) {
40                 condlog(0, "pp->dev too small");
41                 goto out;
42         }
43         if (pathinfo(pp, hwtable, flag))
44                 goto out;
45
46         if (store_path(pathvec, pp))
47                 goto out;
48
49         return pp;
50 out:
51         free_path(pp);
52         return NULL;
53 }
54
55 static int
56 path_discover (vector pathvec, struct config * conf, char * devname, int flag)
57 {
58         char path[FILE_NAME_SIZE];
59         struct path * pp;
60
61         if (!devname)
62                 return 0;
63
64         if (blacklist(conf->blist_devnode, devname))
65                 return 0;
66
67         if(safe_sprintf(path, "%s/block/%s/device", sysfs_path,
68                         devname)) {
69                 condlog(0, "path too small");
70                 return 1;
71         }
72                         
73         if (!filepresent(path))
74                 return 0;
75
76         pp = find_path_by_dev(pathvec, devname);
77
78         if (!pp) {
79                 pp = store_pathinfo(pathvec, conf->hwtable,
80                                     devname, flag);
81                 return (pp ? 0 : 1);
82         }
83         return pathinfo(pp, conf->hwtable, flag);
84 }
85
86 int
87 path_discovery (vector pathvec, struct config * conf, int flag)
88 {
89         struct dlist * ls;
90         struct sysfs_class * class;
91         struct sysfs_class_device * dev;
92         int r = 1;
93
94         if (!(class = sysfs_open_class("block")))
95                 return 1;
96
97         if (!(ls = sysfs_get_class_devices(class)))
98                 goto out;
99
100         r = 0;
101
102         dlist_for_each_data(ls, dev, struct sysfs_class_device)
103                 r += path_discover(pathvec, conf, dev->name, flag);
104
105 out:
106         sysfs_close_class(class);
107         return r;
108 }
109
110 /*
111  * the daemon can race udev upon path add,
112  * not multipath(8), ran by udev
113  */
114 #if DAEMON
115 #define WAIT_MAX_SECONDS 5
116 #define WAIT_LOOP_PER_SECOND 5
117
118 static int
119 wait_for_file (char * filename)
120 {
121         int loop;
122         struct stat stats;
123         
124         loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND;
125         
126         while (--loop) {
127                 if (stat(filename, &stats) == 0)
128                         return 0;
129
130                 if (errno != ENOENT)
131                         return 1;
132
133                 usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
134         }
135         return 1;
136 }
137 #else
138 static int
139 wait_for_file (char * filename)
140 {
141         return 0;
142 }
143 #endif
144
145 #define declare_sysfs_get_str(fname, fmt) \
146 extern int \
147 sysfs_get_##fname (char * sysfs_path, char * dev, char * buff, int len) \
148 { \
149         struct sysfs_attribute * attr; \
150         char attr_path[SYSFS_PATH_SIZE]; \
151 \
152         if (safe_sprintf(attr_path, fmt, sysfs_path, dev)) \
153                 return 1; \
154 \
155         if (wait_for_file(attr_path)) \
156                 return 1; \
157 \
158         if (!(attr = sysfs_open_attribute(attr_path))) \
159                 return 1; \
160 \
161         if (0 > sysfs_read_attribute(attr)) \
162                 goto out; \
163 \
164         if (attr->len < 2 || attr->len - 1 > len) \
165                 goto out; \
166 \
167         strncpy(buff, attr->value, attr->len - 1); \
168         buff[attr->len - 1] = '\0'; \
169         sysfs_close_attribute(attr); \
170         return 0; \
171 out: \
172         sysfs_close_attribute(attr); \
173         return 1; \
174 }
175
176 declare_sysfs_get_str(devtype, "%s/block/%s/device/devtype");
177 declare_sysfs_get_str(cutype, "%s/block/%s/device/cutype");
178 declare_sysfs_get_str(vendor, "%s/block/%s/device/vendor");
179 declare_sysfs_get_str(model, "%s/block/%s/device/model");
180 declare_sysfs_get_str(rev, "%s/block/%s/device/rev");
181 declare_sysfs_get_str(dev, "%s/block/%s/dev");
182
183 int
184 sysfs_get_size (char * sysfs_path, char * dev, unsigned long long * size)
185 {
186         struct sysfs_attribute * attr;
187         char attr_path[SYSFS_PATH_SIZE];
188         int r;
189
190         if (safe_sprintf(attr_path, "%s/block/%s/size", sysfs_path, dev))
191                 return 1;
192
193         attr = sysfs_open_attribute(attr_path);
194
195         if (!attr)
196                 return 1;
197
198         if (0 > sysfs_read_attribute(attr))
199                 goto out;
200
201         r = sscanf(attr->value, "%llu\n", size);
202         sysfs_close_attribute(attr);
203
204         if (r != 1)
205                 return 1;
206
207         return 0;
208 out:
209         sysfs_close_attribute(attr);
210         return 1;
211 }
212         
213 /*
214  * udev might be slow creating node files : wait
215  */
216 static int
217 opennode (char * dev, int mode)
218 {
219         char devpath[FILE_NAME_SIZE];
220
221         if (safe_sprintf(devpath, "%s/%s", conf->udev_dir, dev)) {
222                 condlog(0, "devpath too small");
223                 return -1;
224         }
225
226         if (wait_for_file(devpath)) {
227                 condlog(3, "failed to open %s", devpath);
228                 return -1;
229         }
230
231         return open(devpath, mode);
232 }
233
234 extern int
235 devt2devname (char *devname, char *devt)
236 {
237         struct dlist * ls;
238         char attr_path[FILE_NAME_SIZE];
239         char block_path[FILE_NAME_SIZE];
240         struct sysfs_attribute * attr = NULL;
241         struct sysfs_class * class;
242         struct sysfs_class_device * dev;
243
244         if(safe_sprintf(block_path, "%s/block", sysfs_path)) {
245                 condlog(0, "block_path too small");
246                 return 1;
247         }
248         if (!(class = sysfs_open_class("block")))
249                 return 1;
250
251         if (!(ls = sysfs_get_class_devices(class)))
252                 goto err;
253
254         dlist_for_each_data(ls, dev, struct sysfs_class_device) {
255                 if(safe_sprintf(attr_path, "%s/%s/dev",
256                                 block_path, dev->name)) {
257                         condlog(0, "attr_path too small");
258                         goto err;
259                 }
260                 if (!(attr = sysfs_open_attribute(attr_path)))
261                         goto err;
262
263                 if (sysfs_read_attribute(attr))
264                         goto err1;
265
266                 /* discard newline */
267                 if (attr->len > 1) attr->len--;
268
269                 if (strlen(devt) == attr->len &&
270                     strncmp(attr->value, devt, attr->len) == 0) {
271                         if(safe_sprintf(attr_path, "%s/%s",
272                                         block_path, dev->name)) {
273                                 condlog(0, "attr_path too small");
274                                 goto err1;
275                         }
276                         sysfs_get_name_from_path(attr_path, devname,
277                                                  FILE_NAME_SIZE);
278                         sysfs_close_attribute(attr);
279                         sysfs_close_class(class);
280                         return 0;
281                 }
282         }
283 err1:
284         sysfs_close_attribute(attr);
285 err:
286         sysfs_close_class(class);
287         return 1;
288 }
289
290 static int
291 do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
292        void *resp, int mx_resp_len, int noisy)
293 {
294         unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
295             { INQUIRY_CMD, 0, 0, 0, 0, 0 };
296         unsigned char sense_b[SENSE_BUFF_LEN];
297         struct sg_io_hdr io_hdr;
298                                                                                                                  
299         if (cmddt)
300                 inqCmdBlk[1] |= 2;
301         if (evpd)
302                 inqCmdBlk[1] |= 1;
303         inqCmdBlk[2] = (unsigned char) pg_op;
304         inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff);
305         inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff);
306         memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
307         io_hdr.interface_id = 'S';
308         io_hdr.cmd_len = sizeof (inqCmdBlk);
309         io_hdr.mx_sb_len = sizeof (sense_b);
310         io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
311         io_hdr.dxfer_len = mx_resp_len;
312         io_hdr.dxferp = resp;
313         io_hdr.cmdp = inqCmdBlk;
314         io_hdr.sbp = sense_b;
315         io_hdr.timeout = DEF_TIMEOUT;
316  
317         if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
318                 return -1;
319  
320         /* treat SG_ERR here to get rid of sg_err.[ch] */
321         io_hdr.status &= 0x7e;
322         if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
323             (0 == io_hdr.driver_status))
324                 return 0;
325         if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
326             (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
327             (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
328                 if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
329                         int sense_key;
330                         unsigned char * sense_buffer = io_hdr.sbp;
331                         if (sense_buffer[0] & 0x2)
332                                 sense_key = sense_buffer[1] & 0xf;
333                         else
334                                 sense_key = sense_buffer[2] & 0xf;
335                         if(RECOVERED_ERROR == sense_key)
336                                 return 0;
337                 }
338         }
339         return -1;
340 }
341
342 int
343 get_serial (char * str, int fd)
344 {
345         int len = 0;
346         char buff[MX_ALLOC_LEN + 1] = {0};
347
348         if (fd < 0)
349                 return 0;
350
351         if (0 == do_inq(fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) {
352                 len = buff[3];
353                 if (len > 0) {
354                         memcpy(str, buff + 4, len);
355                         str[len] = '\0';
356                 }
357                 return 1;
358         }
359         return 0;
360 }
361
362 static int
363 sysfs_get_bus (char * sysfs_path, struct path * pp)
364 {
365         struct sysfs_device *sdev;
366         char attr_path[FILE_NAME_SIZE];
367         char attr_buff[FILE_NAME_SIZE];
368
369         pp->bus = SYSFS_BUS_UNDEF;
370
371         /*
372          * This is ugly : we should be able to do a simple
373          * get_link("%s/block/%s/device/bus", ...) but it just
374          * won't work
375          */
376         if(safe_sprintf(attr_path, "%s/block/%s/device",
377                         sysfs_path, pp->dev)) {
378                 condlog(0, "attr_path too small");
379                 return 1;
380         }
381
382         if (0 > sysfs_get_link(attr_path, attr_buff, sizeof(attr_buff)))
383                 return 1;
384
385 #if DAEMON
386         int loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND;
387
388         while (loop--) {
389                 sdev = sysfs_open_device_path(attr_buff);
390
391                 if (strlen(sdev->bus))
392                         break;
393
394                 sysfs_close_device(sdev);
395                 usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
396         }
397 #else
398         sdev = sysfs_open_device_path(attr_buff);
399 #endif
400
401         if (!strncmp(sdev->bus, "scsi", 4))
402                 pp->bus = SYSFS_BUS_SCSI;
403         else if (!strncmp(sdev->bus, "ide", 3))
404                 pp->bus = SYSFS_BUS_IDE;
405         else if (!strncmp(sdev->bus, "ccw", 3))
406                 pp->bus = SYSFS_BUS_CCW;
407         else
408                 return 1;
409
410         sysfs_close_device(sdev);
411
412         return 0;
413 }
414
415 static int
416 scsi_sysfs_pathinfo (struct path * pp)
417 {
418         char attr_path[FILE_NAME_SIZE];
419         char attr_buff[FILE_NAME_SIZE];
420         struct sysfs_attribute * attr;
421
422         if (sysfs_get_vendor(sysfs_path, pp->dev,
423                              pp->vendor_id, SCSI_VENDOR_SIZE))
424                 return 1;
425
426         condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
427
428         if (sysfs_get_model(sysfs_path, pp->dev,
429                             pp->product_id, SCSI_PRODUCT_SIZE))
430                 return 1;
431
432         condlog(3, "%s: product = %s", pp->dev, pp->product_id);
433
434         if (sysfs_get_rev(sysfs_path, pp->dev,
435                           pp->rev, SCSI_REV_SIZE))
436                 return 1;
437
438         condlog(3, "%s: rev = %s", pp->dev, pp->rev);
439
440         /*
441          * set the hwe configlet pointer
442          */
443         pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id);
444
445         /*
446          * host / bus / target / lun
447          */
448         if(safe_sprintf(attr_path, "%s/block/%s/device",
449                         sysfs_path, pp->dev)) {
450                 condlog(0, "attr_path too small");
451                 return 1;
452         }
453         if (0 > sysfs_get_link(attr_path, attr_buff, sizeof(attr_buff)))
454                 return 1;
455         
456         basename(attr_buff, attr_path);
457
458         sscanf(attr_path, "%i:%i:%i:%i",
459                         &pp->sg_id.host_no,
460                         &pp->sg_id.channel,
461                         &pp->sg_id.scsi_id,
462                         &pp->sg_id.lun);
463         condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
464                         pp->dev,
465                         pp->sg_id.host_no,
466                         pp->sg_id.channel,
467                         pp->sg_id.scsi_id,
468                         pp->sg_id.lun);
469
470         /*
471          * target node name
472          */
473         if(safe_sprintf(attr_path,
474                         "%s/class/fc_transport/target%i:%i:%i/node_name",
475                         sysfs_path,
476                         pp->sg_id.host_no,
477                         pp->sg_id.channel,
478                         pp->sg_id.scsi_id)) {
479                 condlog(0, "attr_path too small");
480                 return 1;
481         }
482         if (!(attr = sysfs_open_attribute(attr_path)))
483                 return 0;
484
485         if (sysfs_read_attribute(attr))
486                 goto err;
487
488         if (attr->len > 0)
489                 strncpy(pp->tgt_node_name, attr->value, attr->len - 1);
490
491         condlog(3, "%s: tgt_node_name = %s",
492                 pp->dev, pp->tgt_node_name);
493
494         return 0;
495 err:
496         sysfs_close_attribute(attr);
497         return 1;
498 }
499
500 static int
501 ccw_sysfs_pathinfo (struct path * pp)
502 {
503         char attr_path[FILE_NAME_SIZE];
504         char attr_buff[FILE_NAME_SIZE];
505
506         sprintf(pp->vendor_id, "IBM");
507
508         condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
509
510         if (sysfs_get_devtype(sysfs_path, pp->dev,
511                               attr_buff, FILE_NAME_SIZE))
512                 return 1;
513
514         if (!strncmp(attr_buff, "3370", 4)) {
515                 sprintf(pp->product_id,"S/390 DASD FBA");
516         } else if (!strncmp(attr_buff, "9336", 4)) {
517                 sprintf(pp->product_id,"S/390 DASD FBA");
518         } else {
519                 sprintf(pp->product_id,"S/390 DASD ECKD");
520         }
521
522         condlog(3, "%s: product = %s", pp->dev, pp->product_id);
523
524         /*
525          * set the hwe configlet pointer
526          */
527         pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id);
528
529         /*
530          * host / bus / target / lun
531          */
532         if(safe_sprintf(attr_path, "%s/block/%s/device",
533                         sysfs_path, pp->dev)) {
534                 condlog(0, "attr_path too small");
535                 return 1;
536         }
537         if (0 > sysfs_get_link(attr_path, attr_buff, sizeof(attr_buff)))
538                 return 1;
539         
540         basename(attr_buff, attr_path);
541         pp->sg_id.lun = 0;
542         sscanf(attr_path, "%i.%i.%x",
543                         &pp->sg_id.host_no,
544                         &pp->sg_id.channel,
545                         &pp->sg_id.scsi_id);
546         condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
547                         pp->dev,
548                         pp->sg_id.host_no,
549                         pp->sg_id.channel,
550                         pp->sg_id.scsi_id,
551                         pp->sg_id.lun);
552
553         return 0;
554 }
555
556 static int
557 common_sysfs_pathinfo (struct path * pp)
558 {
559         if (sysfs_get_bus(sysfs_path, pp))
560                 return 1;
561
562         condlog(3, "%s: bus = %i", pp->dev, pp->bus);
563
564         if (sysfs_get_dev(sysfs_path, pp->dev,
565                           pp->dev_t, BLK_DEV_SIZE))
566                 return 1;
567
568         condlog(3, "%s: dev_t = %s", pp->dev, pp->dev_t);
569
570         if (sysfs_get_size(sysfs_path, pp->dev, &pp->size))
571                 return 1;
572
573         condlog(3, "%s: size = %llu", pp->dev, pp->size);
574
575         return 0;
576 }
577
578 extern int
579 sysfs_pathinfo(struct path * pp)
580 {
581         if (common_sysfs_pathinfo(pp))
582                 return 1;
583
584         if (pp->bus == SYSFS_BUS_UNDEF)
585                 return 0;
586         else if (pp->bus == SYSFS_BUS_SCSI) {
587                 if (scsi_sysfs_pathinfo(pp))
588                         return 1;
589         } else if (pp->bus == SYSFS_BUS_CCW) {
590                 if (ccw_sysfs_pathinfo(pp))
591                         return 1;
592         }
593         return 0;
594 }
595
596 static int
597 scsi_ioctl_pathinfo (struct path * pp, int mask)
598 {
599         if (mask & DI_SERIAL) {
600                 get_serial(pp->serial, pp->fd);
601                 condlog(3, "%s: serial = %s", pp->dev, pp->serial);
602         }
603
604         return 0;
605 }
606
607 static int
608 get_state (struct path * pp)
609 {
610         struct checker * c = &pp->checker;
611
612         if (!checker_selected(c)) {
613                 select_checker(pp);
614                 if (!checker_selected(c))
615                         return 1;
616                 checker_set_fd(c, pp->fd);
617                 if (checker_init(c))
618                         return 1;
619         }
620         pp->state = checker_check(c);
621         condlog(3, "%s: state = %i", pp->dev, pp->state);
622         if (pp->state == PATH_DOWN)
623                 condlog(2, "%s: checker msg is \"%s\"",
624                         pp->dev, checker_message(c));
625         return 0;
626 }
627
628 static int
629 get_prio (struct path * pp)
630 {
631         char buff[CALLOUT_MAX_SIZE];
632         char prio[16];
633
634         if (!pp->getprio_selected) {
635                 select_getprio(pp);
636                 pp->getprio_selected = 1;
637         }
638         if (!pp->getprio) {
639                 pp->priority = 1;
640         } else if (apply_format(pp->getprio, &buff[0], pp)) {
641                 condlog(0, "error formatting prio callout command");
642                 pp->priority = -1;
643                 return 1;
644         } else if (execute_program(buff, prio, 16)) {
645                 condlog(0, "error calling out %s", buff);
646                 pp->priority = -1;
647                 return 1;
648         } else
649                 pp->priority = atoi(prio);
650
651         condlog(3, "%s: prio = %u", pp->dev, pp->priority);
652         return 0;
653 }
654
655 static int
656 get_uid (struct path * pp)
657 {
658         char buff[CALLOUT_MAX_SIZE];
659
660         if (!pp->getuid)
661                 select_getuid(pp);
662
663         if (apply_format(pp->getuid, &buff[0], pp)) {
664                 condlog(0, "error formatting uid callout command");
665                 memset(pp->wwid, 0, WWID_SIZE);
666         } else if (execute_program(buff, pp->wwid, WWID_SIZE)) {
667                 condlog(0, "error calling out %s", buff);
668                 memset(pp->wwid, 0, WWID_SIZE);
669                 return 1;
670         }
671         condlog(3, "%s: uid = %s (callout)", pp->dev ,pp->wwid);
672         return 0;
673 }
674
675 extern int
676 pathinfo (struct path *pp, vector hwtable, int mask)
677 {
678         condlog(3, "%s: mask = 0x%x", pp->dev, mask);
679
680         /*
681          * fetch info available in sysfs
682          */
683         if (mask & DI_SYSFS && sysfs_pathinfo(pp))
684                 return 1;
685
686         /*
687          * fetch info not available through sysfs
688          */
689         if (pp->fd < 0)
690                 pp->fd = opennode(pp->dev, O_RDONLY);
691
692         if (pp->fd < 0)
693                 goto blank;
694
695         if (pp->bus == SYSFS_BUS_SCSI &&
696             scsi_ioctl_pathinfo(pp, mask))
697                 goto blank;
698
699         if (mask & DI_CHECKER && get_state(pp))
700                 goto blank;
701         
702         if (mask & DI_PRIO && pp->state != PATH_DOWN)
703                 get_prio(pp);
704
705         if (mask & DI_WWID && !strlen(pp->wwid))
706                 get_uid(pp);
707
708         return 0;
709
710 blank:
711         /*
712          * Recoverable error, for example faulty or offline path
713          */
714         memset(pp->wwid, 0, WWID_SIZE);
715         pp->state = PATH_DOWN;
716         return 0;
717 }