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