multipath: libudev cleanup and bugfixes
[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 <dirent.h>
12 #include <errno.h>
13 #include <libgen.h>
14 #include <libudev.h>
15
16 #include "checkers.h"
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 "sysfs.h"
28 #include "discovery.h"
29 #include "prio.h"
30 #include "defaults.h"
31
32 struct path *
33 store_pathinfo (vector pathvec, vector hwtable, struct udev_device *udevice,
34                 int flag)
35 {
36         struct path * pp;
37         const char * devname;
38
39         devname = udev_device_get_sysname(udevice);
40         if (!devname)
41                 return NULL;
42
43         pp = alloc_path();
44
45         if (!pp)
46                 return NULL;
47
48         if(safe_sprintf(pp->dev, "%s", devname)) {
49                 condlog(0, "pp->dev too small");
50                 goto out;
51         }
52         pp->udev = udev_device_ref(udevice);
53         if (pathinfo(pp, hwtable, flag))
54                 goto out;
55
56         if (store_path(pathvec, pp))
57                 goto out;
58
59         return pp;
60 out:
61         free_path(pp);
62         return NULL;
63 }
64
65 static int
66 path_discover (vector pathvec, struct config * conf,
67                struct udev_device *udevice, int flag)
68 {
69         struct path * pp;
70         const char * devname;
71
72         devname = udev_device_get_sysname(udevice);
73         if (!devname)
74                 return 0;
75
76         if (filter_devnode(conf->blist_devnode, conf->elist_devnode,
77                            (char *)devname) > 0)
78                 return 0;
79
80         pp = find_path_by_dev(pathvec, (char *)devname);
81         if (!pp) {
82                 pp = store_pathinfo(pathvec, conf->hwtable,
83                                     udevice, flag);
84                 return (pp ? 0 : 1);
85         }
86         return pathinfo(pp, conf->hwtable, flag);
87 }
88
89 int
90 path_discovery (vector pathvec, struct config * conf, int flag)
91 {
92         struct udev_enumerate *udev_iter;
93         struct udev_list_entry *entry;
94         struct udev_device *udevice;
95         const char *devpath;
96         int r = 0;
97
98         udev_iter = udev_enumerate_new(conf->udev);
99         if (!udev_iter)
100                 return 1;
101
102         udev_enumerate_add_match_subsystem(udev_iter, "block");
103         udev_enumerate_scan_devices(udev_iter);
104
105         udev_list_entry_foreach(entry,
106                                 udev_enumerate_get_list_entry(udev_iter)) {
107                 devpath = udev_list_entry_get_name(entry);
108                 condlog(4, "Discover device %s", devpath);
109                 udevice = udev_device_new_from_syspath(conf->udev, devpath);
110                 if (!udevice) {
111                         condlog(4, "%s: no udev information", devpath);
112                         r++;
113                         continue;
114                 }
115                 if(!strncmp(udev_device_get_devtype(udevice), "disk", 4))
116                         r += path_discover(pathvec, conf, udevice, flag);
117                 udev_device_unref(udevice);
118         }
119         udev_enumerate_unref(udev_iter);
120         condlog(4, "Discovery status %d", r);
121         return r;
122 }
123
124 #define declare_sysfs_get_str(fname)                                    \
125 extern int                                                              \
126 sysfs_get_##fname (struct udev_device * udev, char * buff, size_t len)  \
127 {                                                                       \
128         const char * attr;                                              \
129         const char * devname;                                           \
130                                                                         \
131         devname = udev_device_get_sysname(udev);                        \
132                                                                         \
133         attr = udev_device_get_sysattr_value(udev, #fname);             \
134         if (!attr) {                                                    \
135                 condlog(3, "%s: attribute %s not found in sysfs",       \
136                         devname, #fname);                               \
137                 return 1;                                               \
138         }                                                               \
139         if (strlen(attr) > len) {                                       \
140                 condlog(3, "%s: overflow in attribute %s",              \
141                         devname, #fname);                               \
142                 return 2;                                               \
143         }                                                               \
144         strlcpy(buff, attr, len);                                       \
145         return 0;                                                       \
146 }
147
148 declare_sysfs_get_str(devtype);
149 declare_sysfs_get_str(cutype);
150 declare_sysfs_get_str(vendor);
151 declare_sysfs_get_str(model);
152 declare_sysfs_get_str(rev);
153 declare_sysfs_get_str(state);
154 declare_sysfs_get_str(dev);
155
156 int
157 sysfs_get_timeout(struct path *pp, unsigned int *timeout)
158 {
159         const char *attr = NULL;
160         const char *subsys;
161         struct udev_device *parent;
162         int r;
163         unsigned int t;
164
165         if (!pp->udev || pp->bus != SYSFS_BUS_SCSI)
166                 return 1;
167
168         parent = pp->udev;
169         while (parent) {
170                 subsys = udev_device_get_subsystem(parent);
171                 attr = udev_device_get_sysattr_value(parent, "timeout");
172                 if (subsys && attr)
173                         break;
174                 parent = udev_device_get_parent(parent);
175         }
176         if (!attr) {
177                 condlog(3, "%s: No timeout value in sysfs", pp->dev);
178                 return 1;
179         }
180
181         r = sscanf(attr, "%u\n", &t);
182
183         if (r != 1) {
184                 condlog(3, "%s: Cannot parse timeout attribute '%s'",
185                         pp->dev, attr);
186                 return 1;
187         }
188
189         *timeout = t * 1000;
190
191         return 0;
192 }
193
194 int
195 sysfs_get_tgt_nodename (struct path *pp, char * node)
196 {
197         const char *targetid, *value;
198         struct udev_device *parent, *tgtdev;
199
200         parent = udev_device_get_parent_with_subsystem_devtype(pp->udev, "scsi", "scsi_device");
201         if (!parent)
202                 return 1;
203         /* Check for SAS */
204         value = udev_device_get_sysattr_value(parent, "sas_address");
205         if (value) {
206                 strncpy(node, value, NODE_NAME_SIZE);
207                 return 0;
208         }
209
210         parent = udev_device_get_parent_with_subsystem_devtype(pp->udev, "scsi", "scsi_target");
211         if (!parent)
212                 return 1;
213         tgtdev = udev_device_new_from_subsystem_sysname(conf->udev, "fc_transport", udev_device_get_sysname(parent));
214         /* Check if it's FibreChannel */
215         if (tgtdev) {
216                 const char *value;
217
218                 value = udev_device_get_sysattr_value(tgtdev, "node_name");
219                 udev_device_unref(tgtdev);
220                 if (value) {
221                         strncpy(node, value, NODE_NAME_SIZE);
222                         return 0;
223                 }
224         }
225
226         /* Check for iSCSI */
227         parent = pp->udev;
228         targetid = NULL;
229         while (parent) {
230                 targetid = udev_device_get_sysname(parent);
231                 if (!strncmp(targetid , "session", 6))
232                         break;
233                 parent = udev_device_get_parent(parent);
234                 targetid = NULL;
235         }
236         if (parent) {
237                 tgtdev = udev_device_new_from_subsystem_sysname(conf->udev, "iscsi_session", targetid);
238                 if (tgtdev) {
239                         const char *value;
240
241                         value = udev_device_get_sysattr_value(tgtdev, "targetname");
242                         udev_device_unref(tgtdev);
243                         if (value) {
244                                 strncpy(node, value, NODE_NAME_SIZE);
245                                 return 0;
246                         }
247                 }
248         }
249         return 1;
250 }
251
252 static void
253 sysfs_set_rport_tmo(struct multipath *mpp, struct path *pp)
254 {
255         struct udev_device *parent = pp->udev;
256         struct udev_device *rport_dev = NULL;
257         char value[11];
258         const char *rport_id = NULL;
259
260         while (parent) {
261                 rport_id = udev_device_get_sysname(parent);
262                 if (!strncmp(rport_id, "rport-", 6))
263                         break;
264                 parent = udev_device_get_parent(parent);
265                 rport_id = NULL;
266         }
267         if (!parent || !rport_id) {
268                 condlog(0, "%s: rport id not found", pp->dev);
269                 return;
270         }
271         rport_dev = udev_device_new_from_subsystem_sysname(conf->udev, "fc_remote_ports", rport_id);
272         if (!rport_dev) {
273                 condlog(3, "%s: No fc_remote_port device for '%s'", pp->dev,
274                         rport_id);
275                 return;
276         }
277         condlog(4, "target%d:%d:%d -> %s", pp->sg_id.host_no,
278                 pp->sg_id.channel, pp->sg_id.scsi_id, rport_id);
279
280         snprintf(value, 11, "%u", mpp->dev_loss);
281         if (sysfs_attr_set_value(rport_dev, "dev_loss_tmo", value, 11) < 0) {
282                 if ((!mpp->fast_io_fail ||
283                      mpp->fast_io_fail == MP_FAST_IO_FAIL_OFF)
284                     && mpp->dev_loss > 600) {
285                         condlog(3, "%s: limiting dev_loss_tmo to 600, since "
286                                 "fast_io_fail is not set", mpp->alias);
287                         snprintf(value, 11, "%u", 600);
288                         if (sysfs_attr_set_value(rport_dev, "dev_loss_tmo",
289                                                  value, 11) < 0)
290                                 condlog(0, "%s failed to set dev_loss_tmo",
291                                         mpp->alias);
292                         goto out;
293                 }
294         }
295         if (mpp->fast_io_fail){
296                 if (mpp->fast_io_fail == MP_FAST_IO_FAIL_OFF)
297                         sprintf(value, "off");
298                 else if (mpp->fast_io_fail == MP_FAST_IO_FAIL_ZERO)
299                         sprintf(value, "0");
300                 else
301                         snprintf(value, 11, "%u", mpp->fast_io_fail);
302                 if (sysfs_attr_set_value(rport_dev, "fast_io_fail_tmo",
303                                          value, 11) < 0) {
304                         condlog(0, "%s failed to set fast_io_fail_tmo",
305                                 mpp->alias);
306                 }
307         }
308 out:
309         udev_device_unref(rport_dev);
310 }
311
312 int
313 sysfs_set_scsi_tmo (struct multipath *mpp)
314 {
315         struct path *pp;
316         int i;
317         int dev_loss_tmo = mpp->dev_loss;
318
319         if (mpp->no_path_retry > 0) {
320                 int no_path_retry_tmo = mpp->no_path_retry * conf->checkint;
321
322                 if (no_path_retry_tmo > MAX_DEV_LOSS_TMO)
323                         no_path_retry_tmo = MAX_DEV_LOSS_TMO;
324                 if (no_path_retry_tmo > dev_loss_tmo)
325                         dev_loss_tmo = no_path_retry_tmo;
326                 condlog(3, "%s: update dev_loss_tmo to %d",
327                         mpp->alias, dev_loss_tmo);
328         } else if (mpp->no_path_retry == NO_PATH_RETRY_QUEUE) {
329                 dev_loss_tmo = MAX_DEV_LOSS_TMO;
330                 condlog(3, "%s: update dev_loss_tmo to %d",
331                         mpp->alias, dev_loss_tmo);
332         }
333         mpp->dev_loss = dev_loss_tmo;
334         if (mpp->dev_loss && mpp->fast_io_fail >= (int)mpp->dev_loss) {
335                 condlog(3, "%s: turning off fast_io_fail (%d is not smaller than dev_loss_tmo)",
336                         mpp->alias, mpp->fast_io_fail);
337                 mpp->fast_io_fail = MP_FAST_IO_FAIL_OFF;
338         }
339         if (!mpp->dev_loss && !mpp->fast_io_fail)
340                 return 0;
341
342         vector_foreach_slot(mpp->paths, pp, i) {
343                 sysfs_set_rport_tmo(mpp, pp);
344         }
345         return 0;
346 }
347
348 int
349 do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
350        void *resp, int mx_resp_len)
351 {
352         unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
353                 { INQUIRY_CMD, 0, 0, 0, 0, 0 };
354         unsigned char sense_b[SENSE_BUFF_LEN];
355         struct sg_io_hdr io_hdr;
356
357         if (cmddt)
358                 inqCmdBlk[1] |= 2;
359         if (evpd)
360                 inqCmdBlk[1] |= 1;
361         inqCmdBlk[2] = (unsigned char) pg_op;
362         inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff);
363         inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff);
364         memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
365         memset(sense_b, 0, SENSE_BUFF_LEN);
366         io_hdr.interface_id = 'S';
367         io_hdr.cmd_len = sizeof (inqCmdBlk);
368         io_hdr.mx_sb_len = sizeof (sense_b);
369         io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
370         io_hdr.dxfer_len = mx_resp_len;
371         io_hdr.dxferp = resp;
372         io_hdr.cmdp = inqCmdBlk;
373         io_hdr.sbp = sense_b;
374         io_hdr.timeout = DEF_TIMEOUT;
375
376         if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
377                 return -1;
378
379         /* treat SG_ERR here to get rid of sg_err.[ch] */
380         io_hdr.status &= 0x7e;
381         if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
382             (0 == io_hdr.driver_status))
383                 return 0;
384         if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
385             (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
386             (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
387                 if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
388                         int sense_key;
389                         unsigned char * sense_buffer = io_hdr.sbp;
390                         if (sense_buffer[0] & 0x2)
391                                 sense_key = sense_buffer[1] & 0xf;
392                         else
393                                 sense_key = sense_buffer[2] & 0xf;
394                         if(RECOVERED_ERROR == sense_key)
395                                 return 0;
396                 }
397         }
398         return -1;
399 }
400
401 static int
402 get_serial (char * str, int maxlen, int fd)
403 {
404         int len = 0;
405         char buff[MX_ALLOC_LEN + 1] = {0};
406
407         if (fd < 0)
408                 return 1;
409
410         if (0 == do_inq(fd, 0, 1, 0x80, buff, MX_ALLOC_LEN)) {
411                 len = buff[3];
412                 if (len >= maxlen)
413                         return 1;
414                 if (len > 0) {
415                         memcpy(str, buff + 4, len);
416                         str[len] = '\0';
417                 }
418                 return 0;
419         }
420         return 1;
421 }
422
423 static int
424 get_geometry(struct path *pp)
425 {
426         if (pp->fd < 0)
427                 return 1;
428
429         if (ioctl(pp->fd, HDIO_GETGEO, &pp->geom)) {
430                 condlog(2, "%s: HDIO_GETGEO failed with %d", pp->dev, errno);
431                 memset(&pp->geom, 0, sizeof(pp->geom));
432                 return 1;
433         }
434         condlog(3, "%s: %u cyl, %u heads, %u sectors/track, start at %lu",
435                 pp->dev, pp->geom.cylinders, pp->geom.heads,
436                 pp->geom.sectors, pp->geom.start);
437         return 0;
438 }
439
440 static int
441 scsi_sysfs_pathinfo (struct path * pp)
442 {
443         struct udev_device *parent;
444         const char *attr_path = NULL;
445
446         parent = pp->udev;
447         while (parent) {
448                 if (!strncmp(udev_device_get_subsystem(parent), "scsi", 4)) {
449                         attr_path = udev_device_get_sysname(parent);
450                         if (!attr_path)
451                                 break;
452                         if (sscanf(attr_path, "%i:%i:%i:%i",
453                                    &pp->sg_id.host_no,
454                                    &pp->sg_id.channel,
455                                    &pp->sg_id.scsi_id,
456                                    &pp->sg_id.lun) == 4)
457                                 break;
458                 }
459                 parent = udev_device_get_parent(parent);
460         }
461         if (!attr_path || pp->sg_id.host_no == -1)
462                 return 1;
463
464         if (sysfs_get_vendor(parent, pp->vendor_id, SCSI_VENDOR_SIZE))
465                 return 1;
466
467         condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
468
469         if (sysfs_get_model(parent, pp->product_id, SCSI_PRODUCT_SIZE))
470                 return 1;
471
472         condlog(3, "%s: product = %s", pp->dev, pp->product_id);
473
474         if (sysfs_get_rev(parent, pp->rev, SCSI_REV_SIZE))
475                 return 1;
476
477         condlog(3, "%s: rev = %s", pp->dev, pp->rev);
478
479         /*
480          * set the hwe configlet pointer
481          */
482         pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, pp->rev);
483
484         /*
485          * host / bus / target / lun
486          */
487         condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
488                         pp->dev,
489                         pp->sg_id.host_no,
490                         pp->sg_id.channel,
491                         pp->sg_id.scsi_id,
492                         pp->sg_id.lun);
493
494         /*
495          * target node name
496          */
497         if(!sysfs_get_tgt_nodename(pp, pp->tgt_node_name)) {
498                 condlog(3, "%s: tgt_node_name = %s",
499                         pp->dev, pp->tgt_node_name);
500         }
501
502         return 0;
503 }
504
505 static int
506 ccw_sysfs_pathinfo (struct path * pp)
507 {
508         struct udev_device *parent;
509         char attr_buff[NAME_SIZE];
510         const char *attr_path;
511
512         parent = pp->udev;
513         while (parent) {
514                 if (!strncmp(udev_device_get_subsystem(parent), "ccw", 3))
515                         break;
516                 parent = udev_device_get_parent(parent);
517         }
518         if (!parent)
519                 return 1;
520
521         sprintf(pp->vendor_id, "IBM");
522
523         condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
524
525         if (sysfs_get_devtype(parent, attr_buff, FILE_NAME_SIZE))
526                 return 1;
527
528         if (!strncmp(attr_buff, "3370", 4)) {
529                 sprintf(pp->product_id,"S/390 DASD FBA");
530         } else if (!strncmp(attr_buff, "9336", 4)) {
531                 sprintf(pp->product_id,"S/390 DASD FBA");
532         } else {
533                 sprintf(pp->product_id,"S/390 DASD ECKD");
534         }
535
536         condlog(3, "%s: product = %s", pp->dev, pp->product_id);
537
538         /*
539          * set the hwe configlet pointer
540          */
541         pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, NULL);
542
543         /*
544          * host / bus / target / lun
545          */
546         attr_path = udev_device_get_sysname(parent);
547         pp->sg_id.lun = 0;
548         sscanf(attr_path, "%i.%i.%x",
549                         &pp->sg_id.host_no,
550                         &pp->sg_id.channel,
551                         &pp->sg_id.scsi_id);
552         condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
553                         pp->dev,
554                         pp->sg_id.host_no,
555                         pp->sg_id.channel,
556                         pp->sg_id.scsi_id,
557                         pp->sg_id.lun);
558
559         return 0;
560 }
561
562 static int
563 cciss_sysfs_pathinfo (struct path * pp)
564 {
565         const char * attr_path = NULL;
566         struct udev_device *parent;
567
568         parent = pp->udev;
569         while (parent) {
570                 if (!strncmp(udev_device_get_subsystem(parent), "cciss", 5)) {
571                         attr_path = udev_device_get_sysname(parent);
572                         if (!attr_path)
573                                 break;
574                         if (sscanf(attr_path, "c%id%i",
575                                    &pp->sg_id.host_no,
576                                    &pp->sg_id.scsi_id) == 2)
577                                 break;
578                 }
579                 parent = udev_device_get_parent(parent);
580         }
581         if (!attr_path || pp->sg_id.host_no == -1)
582                 return 1;
583
584         if (sysfs_get_vendor(parent, pp->vendor_id, SCSI_VENDOR_SIZE))
585                 return 1;
586
587         condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
588
589         if (sysfs_get_model(parent, pp->product_id, SCSI_PRODUCT_SIZE))
590                 return 1;
591
592         condlog(3, "%s: product = %s", pp->dev, pp->product_id);
593
594         if (sysfs_get_rev(parent, pp->rev, SCSI_REV_SIZE))
595                 return 1;
596
597         condlog(3, "%s: rev = %s", pp->dev, pp->rev);
598
599         /*
600          * set the hwe configlet pointer
601          */
602         pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, pp->rev);
603
604         /*
605          * host / bus / target / lun
606          */
607         pp->sg_id.lun = 0;
608         pp->sg_id.channel = 0;
609         condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
610                 pp->dev,
611                 pp->sg_id.host_no,
612                 pp->sg_id.channel,
613                 pp->sg_id.scsi_id,
614                 pp->sg_id.lun);
615         return 0;
616 }
617
618 static int
619 common_sysfs_pathinfo (struct path * pp)
620 {
621         if (!pp->udev) {
622                 condlog(4, "%s: udev not initialised", pp->dev);
623                 return 1;
624         }
625         if (sysfs_get_dev(pp->udev, pp->dev_t, BLK_DEV_SIZE)) {
626                 condlog(3, "%s: no 'dev' attribute in sysfs", pp->dev);
627                 return 1;
628         }
629
630         condlog(3, "%s: dev_t = %s", pp->dev, pp->dev_t);
631
632         if (sysfs_get_size(pp, &pp->size))
633                 return 1;
634
635         condlog(3, "%s: size = %llu", pp->dev, pp->size);
636
637         return 0;
638 }
639
640 int
641 path_offline (struct path * pp)
642 {
643         struct udev_device * parent;
644         char buff[SCSI_STATE_SIZE];
645
646         if (pp->bus != SYSFS_BUS_SCSI)
647                 return PATH_UP;
648
649         parent = pp->udev;
650         while (parent) {
651                 if (!strncmp(udev_device_get_subsystem(parent), "scsi", 4))
652                         break;
653                 parent = udev_device_get_parent(parent);
654         }
655
656         if (!parent) {
657                 condlog(1, "%s: failed to get sysfs information", pp->dev);
658                 return PATH_WILD;
659         }
660
661         if (sysfs_get_state(parent, buff, SCSI_STATE_SIZE))
662                 return PATH_WILD;
663
664         condlog(3, "%s: path state = %s", pp->dev, buff);
665
666         if (!strncmp(buff, "offline", 7)) {
667                 pp->offline = 1;
668                 return PATH_DOWN;
669         }
670         pp->offline = 0;
671         if (!strncmp(buff, "blocked", 7))
672                 return PATH_PENDING;
673         else if (!strncmp(buff, "running", 7))
674                 return PATH_UP;
675
676         return PATH_DOWN;
677 }
678
679 extern int
680 sysfs_pathinfo(struct path * pp)
681 {
682         if (common_sysfs_pathinfo(pp))
683                 return 1;
684
685         pp->bus = SYSFS_BUS_UNDEF;
686         if (!strncmp(pp->dev,"cciss",5))
687                 pp->bus = SYSFS_BUS_CCISS;
688         if (!strncmp(pp->dev,"dasd", 4))
689                 pp->bus = SYSFS_BUS_CCW;
690         if (!strncmp(pp->dev,"sd", 2))
691                 pp->bus = SYSFS_BUS_SCSI;
692
693         if (pp->bus == SYSFS_BUS_UNDEF)
694                 return 0;
695         else if (pp->bus == SYSFS_BUS_SCSI) {
696                 if (scsi_sysfs_pathinfo(pp))
697                         return 1;
698         } else if (pp->bus == SYSFS_BUS_CCW) {
699                 if (ccw_sysfs_pathinfo(pp))
700                         return 1;
701         } else if (pp->bus == SYSFS_BUS_CCISS) {
702                 if (cciss_sysfs_pathinfo(pp))
703                         return 1;
704         }
705         return 0;
706 }
707
708 static int
709 scsi_ioctl_pathinfo (struct path * pp, int mask)
710 {
711         if (mask & DI_SERIAL) {
712                 get_serial(pp->serial, SERIAL_SIZE, pp->fd);
713                 condlog(3, "%s: serial = %s", pp->dev, pp->serial);
714         }
715
716         return 0;
717 }
718
719 static int
720 cciss_ioctl_pathinfo (struct path * pp, int mask)
721 {
722         if (mask & DI_SERIAL) {
723                 get_serial(pp->serial, SERIAL_SIZE, pp->fd);
724                 condlog(3, "%s: serial = %s", pp->dev, pp->serial);
725         }
726         return 0;
727 }
728
729 int
730 get_state (struct path * pp, int daemon)
731 {
732         struct checker * c = &pp->checker;
733         int state;
734
735         condlog(3, "%s: get_state", pp->dev);
736
737         if (!checker_selected(c)) {
738                 if (daemon) {
739                         if (pathinfo(pp, conf->hwtable, DI_SYSFS) != 0) {
740                                 condlog(3, "%s: couldn't get sysfs pathinfo",
741                                         pp->dev);
742                                 return PATH_UNCHECKED;
743                         }
744                 }
745                 select_checker(pp);
746                 if (!checker_selected(c)) {
747                         condlog(3, "%s: No checker selected", pp->dev);
748                         return PATH_UNCHECKED;
749                 }
750                 checker_set_fd(c, pp->fd);
751                 if (checker_init(c, pp->mpp?&pp->mpp->mpcontext:NULL)) {
752                         memset(c, 0x0, sizeof(struct checker));
753                         condlog(3, "%s: checker init failed", pp->dev);
754                         return PATH_UNCHECKED;
755                 }
756         }
757         checker_clear_message(c);
758         if (daemon)
759                 checker_set_async(c);
760         if (!conf->checker_timeout)
761                 sysfs_get_timeout(pp, &(c->timeout));
762         state = checker_check(c);
763         condlog(3, "%s: state = %s", pp->dev, checker_state_name(state));
764         if (state == PATH_DOWN && strlen(checker_message(c)))
765                 condlog(3, "%s: checker msg is \"%s\"",
766                         pp->dev, checker_message(c));
767         return state;
768 }
769
770 static int
771 get_prio (struct path * pp)
772 {
773         if (!pp)
774                 return 0;
775
776         if (!pp->prio) {
777                 select_prio(pp);
778                 if (!pp->prio) {
779                         condlog(3, "%s: no prio selected", pp->dev);
780                         return 1;
781                 }
782         }
783         pp->priority = prio_getprio(pp->prio, pp);
784         if (pp->priority < 0) {
785                 condlog(3, "%s: %s prio error", pp->dev, prio_name(pp->prio));
786                 pp->priority = PRIO_UNDEF;
787                 return 1;
788         }
789         condlog(3, "%s: %s prio = %u",
790                 pp->dev, prio_name(pp->prio), pp->priority);
791         return 0;
792 }
793
794 static int
795 get_uid (struct path * pp)
796 {
797         char *c;
798         const char *value;
799
800         if (!pp->uid_attribute)
801                 select_getuid(pp);
802
803         if (!pp->udev) {
804                 condlog(1, "%s: no udev information", pp->dev);
805                 return 1;
806         }
807
808         memset(pp->wwid, 0, WWID_SIZE);
809         value = udev_device_get_property_value(pp->udev, pp->uid_attribute);
810         if (value && strlen(value)) {
811                 size_t len = WWID_SIZE;
812
813                 if (strlen(value) + 1 > WWID_SIZE) {
814                         condlog(0, "%s: wwid overflow", pp->dev);
815                 } else {
816                         len = strlen(value);
817                 }
818                 strncpy(pp->wwid, value, len);
819         } else {
820                 condlog(3, "%s: no %s attribute", pp->dev,
821                         pp->uid_attribute);
822         }
823
824         /* Strip any trailing blanks */
825         c = strchr(pp->wwid, '\0');
826         c--;
827         while (c && c >= pp->wwid && *c == ' ') {
828                 *c = '\0';
829                 c--;
830         }
831         condlog(3, "%s: uid = %s (udev)", pp->dev,
832                 *pp->wwid == '\0' ? "<empty>" : pp->wwid);
833         return 0;
834 }
835
836 extern int
837 pathinfo (struct path *pp, vector hwtable, int mask)
838 {
839         int path_state;
840
841         condlog(3, "%s: mask = 0x%x", pp->dev, mask);
842
843         /*
844          * fetch info available in sysfs
845          */
846         if (mask & DI_SYSFS && sysfs_pathinfo(pp))
847                 return 1;
848
849         path_state = path_offline(pp);
850
851         /*
852          * fetch info not available through sysfs
853          */
854         if (pp->fd < 0)
855                 pp->fd = open(udev_device_get_devnode(pp->udev), O_RDWR);
856
857         if (pp->fd < 0) {
858                 condlog(4, "Couldn't open node for %s: %s",
859                         pp->dev, strerror(errno));
860                 goto blank;
861         }
862
863         if (mask & DI_SERIAL)
864                 get_geometry(pp);
865
866         if (path_state == PATH_UP && pp->bus == SYSFS_BUS_SCSI &&
867             scsi_ioctl_pathinfo(pp, mask))
868                 goto blank;
869
870         if (pp->bus == SYSFS_BUS_CCISS &&
871             cciss_ioctl_pathinfo(pp, mask))
872                 goto blank;
873
874         if (mask & DI_CHECKER) {
875                 if (path_state == PATH_UP) {
876                         pp->state = get_state(pp, 0);
877                         if (pp->state == PATH_UNCHECKED ||
878                             pp->state == PATH_WILD)
879                                 goto blank;
880                 } else {
881                         condlog(3, "%s: path inaccessible", pp->dev);
882                         pp->state = path_state;
883                 }
884         }
885
886          /*
887           * Retrieve path priority, even for PATH_DOWN paths if it has never
888           * been successfully obtained before.
889           */
890         if ((mask & DI_PRIO) && path_state == PATH_UP) {
891                 if (pp->state != PATH_DOWN || pp->priority == PRIO_UNDEF) {
892                         if (!strlen(pp->wwid))
893                                 get_uid(pp);
894                         get_prio(pp);
895                 } else {
896                         pp->priority = PRIO_UNDEF;
897                 }
898         }
899
900         if (path_state == PATH_UP && (mask & DI_WWID) && !strlen(pp->wwid))
901                 get_uid(pp);
902
903         return 0;
904
905 blank:
906         /*
907          * Recoverable error, for example faulty or offline path
908          */
909         memset(pp->wwid, 0, WWID_SIZE);
910         pp->state = PATH_DOWN;
911
912         return 0;
913 }