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