Set recovery_tmo for iSCSI devices
[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         int host, channel, rport_id = -1, ata_id = -1;
211
212         parent = udev_device_get_parent_with_subsystem_devtype(pp->udev, "scsi", "scsi_device");
213         if (!parent)
214                 return 1;
215         /* Check for SAS */
216         value = udev_device_get_sysattr_value(parent, "sas_address");
217         if (value) {
218                 pp->sg_id.proto_id = SCSI_PROTOCOL_SAS;
219                 strncpy(node, value, NODE_NAME_SIZE);
220                 return 0;
221         }
222
223         parent = udev_device_get_parent_with_subsystem_devtype(pp->udev, "scsi", "scsi_target");
224         if (!parent)
225                 return 1;
226         /* Check for FibreChannel */
227         tgtdev = udev_device_get_parent(parent);
228         value = udev_device_get_sysname(tgtdev);
229         if (sscanf(value, "rport-%d:%d-%d",
230                    &host, &channel, &rport_id) == 3) {
231                 tgtdev = udev_device_new_from_subsystem_sysname(conf->udev,
232                                 "fc_remote_ports", value);
233                 if (tgtdev) {
234                         condlog(3, "SCSI target %d:%d:%d -> "
235                                 "FC rport %d:%d-%d",
236                                 pp->sg_id.host_no, pp->sg_id.channel,
237                                 pp->sg_id.scsi_id, host, channel,
238                                 rport_id);
239                         value = udev_device_get_sysattr_value(tgtdev,
240                                                               "node_name");
241                         if (value) {
242                                 pp->sg_id.proto_id = SCSI_PROTOCOL_FCP;
243                                 pp->sg_id.transport_id = rport_id;
244                                 strncpy(node, value, NODE_NAME_SIZE);
245                                 udev_device_unref(tgtdev);
246                                 return 0;
247                         } else
248                                 udev_device_unref(tgtdev);
249                 }
250         }
251
252         /* Check for iSCSI */
253         parent = pp->udev;
254         targetid = NULL;
255         while (parent) {
256                 targetid = udev_device_get_sysname(parent);
257                 if (targetid && sscanf(targetid , "session%d", &rport_id) == 1)
258                         break;
259                 parent = udev_device_get_parent(parent);
260                 targetid = NULL;
261                 rport_id = -1;
262         }
263         if (parent && targetid) {
264                 tgtdev = udev_device_new_from_subsystem_sysname(conf->udev,
265                                 "iscsi_session", targetid);
266                 if (tgtdev) {
267                         const char *value;
268
269                         value = udev_device_get_sysattr_value(tgtdev, "targetname");
270                         if (value) {
271                                 pp->sg_id.proto_id = SCSI_PROTOCOL_ISCSI;
272                                 pp->sg_id.transport_id = rport_id;
273                                 strncpy(node, value, NODE_NAME_SIZE);
274                                 udev_device_unref(tgtdev);
275                                 return 0;
276                         }
277                         else
278                                 udev_device_unref(tgtdev);
279                 }
280         }
281         /* Check for libata */
282         parent = pp->udev;
283         targetid = NULL;
284         while (parent) {
285                 targetid = udev_device_get_sysname(parent);
286                 if (targetid && sscanf(targetid, "ata%d", &ata_id) == 1)
287                         break;
288                 parent = udev_device_get_parent(parent);
289                 targetid = NULL;
290         }
291         if (targetid) {
292                 pp->sg_id.proto_id = SCSI_PROTOCOL_ATA;
293                 pp->sg_id.transport_id = ata_id;
294                 snprintf(node, NODE_NAME_SIZE, "ata-%d.00", ata_id);
295                 return 0;
296         }
297         pp->sg_id.proto_id = SCSI_PROTOCOL_UNSPEC;
298         return 1;
299 }
300
301 static void
302 sysfs_set_rport_tmo(struct multipath *mpp, struct path *pp)
303 {
304         struct udev_device *rport_dev = NULL;
305         char value[11];
306         char rport_id[32];
307
308         sprintf(rport_id, "rport-%d:%d-%d",
309                 pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id);
310         rport_dev = udev_device_new_from_subsystem_sysname(conf->udev,
311                                 "fc_remote_ports", rport_id);
312         if (!rport_dev) {
313                 condlog(1, "%s: No fc_remote_port device for '%s'", pp->dev,
314                         rport_id);
315                 return;
316         }
317         condlog(4, "target%d:%d:%d -> %s", pp->sg_id.host_no,
318                 pp->sg_id.channel, pp->sg_id.scsi_id, rport_id);
319
320         snprintf(value, 11, "%u", mpp->dev_loss);
321         if (mpp->dev_loss &&
322             sysfs_attr_set_value(rport_dev, "dev_loss_tmo", value, 11) <= 0) {
323                 if ((mpp->fast_io_fail == MP_FAST_IO_FAIL_UNSET ||
324                      mpp->fast_io_fail == MP_FAST_IO_FAIL_OFF)
325                     && mpp->dev_loss > 600) {
326                         condlog(3, "%s: limiting dev_loss_tmo to 600, since "
327                                 "fast_io_fail is not set", mpp->alias);
328                         snprintf(value, 11, "%u", 600);
329                         if (sysfs_attr_set_value(rport_dev, "dev_loss_tmo",
330                                                  value, 11) <= 0)
331                                 condlog(0, "%s failed to set dev_loss_tmo",
332                                         mpp->alias);
333                         goto out;
334                 }
335         }
336         if (mpp->fast_io_fail != MP_FAST_IO_FAIL_UNSET){
337                 if (mpp->fast_io_fail == MP_FAST_IO_FAIL_OFF)
338                         sprintf(value, "off");
339                 else if (mpp->fast_io_fail == MP_FAST_IO_FAIL_ZERO)
340                         sprintf(value, "0");
341                 else
342                         snprintf(value, 11, "%u", mpp->fast_io_fail);
343                 if (sysfs_attr_set_value(rport_dev, "fast_io_fail_tmo",
344                                          value, 11) <= 0) {
345                         condlog(0, "%s failed to set fast_io_fail_tmo",
346                                 mpp->alias);
347                 }
348         }
349 out:
350         udev_device_unref(rport_dev);
351 }
352
353 static void
354 sysfs_set_session_tmo(struct multipath *mpp, struct path *pp)
355 {
356         struct udev_device *session_dev = NULL;
357         char session_id[64];
358         char value[11];
359
360         sprintf(session_id, "session%d", pp->sg_id.transport_id);
361         session_dev = udev_device_new_from_subsystem_sysname(conf->udev,
362                                 "iscsi_session", session_id);
363         if (!session_dev) {
364                 condlog(1, "%s: No iscsi session for '%s'", pp->dev,
365                         session_id);
366                 return;
367         }
368         condlog(4, "target%d:%d:%d -> %s", pp->sg_id.host_no,
369                 pp->sg_id.channel, pp->sg_id.scsi_id, session_id);
370
371         if (mpp->dev_loss) {
372                 condlog(3, "%s: ignoring dev_loss_tmo on iSCSI", pp->dev);
373         }
374         if (mpp->fast_io_fail != MP_FAST_IO_FAIL_UNSET) {
375                 if (mpp->fast_io_fail == MP_FAST_IO_FAIL_OFF) {
376                         condlog(3, "%s: can't switch off fast_io_fail_tmo "
377                                 "on iSCSI", pp->dev);
378                 } else if (mpp->fast_io_fail == MP_FAST_IO_FAIL_ZERO) {
379                         condlog(3, "%s: can't set fast_io_fail_tmo to '0'"
380                                 "on iSCSI", pp->dev);
381                 } else {
382                         snprintf(value, 11, "%u", mpp->fast_io_fail);
383                         if (sysfs_attr_set_value(session_dev, "recovery_tmo",
384                                                  value, 11)) {
385                                 condlog(3, "%s: Failed to set recovery_tmo, "
386                                         " error %d", pp->dev, errno);
387                         }
388                 }
389         }
390         udev_device_unref(session_dev);
391         return;
392 }
393
394 int
395 sysfs_set_scsi_tmo (struct multipath *mpp)
396 {
397         struct path *pp;
398         int i;
399         int dev_loss_tmo = mpp->dev_loss;
400
401         if (mpp->no_path_retry > 0) {
402                 int no_path_retry_tmo = mpp->no_path_retry * conf->checkint;
403
404                 if (no_path_retry_tmo > MAX_DEV_LOSS_TMO)
405                         no_path_retry_tmo = MAX_DEV_LOSS_TMO;
406                 if (no_path_retry_tmo > dev_loss_tmo)
407                         dev_loss_tmo = no_path_retry_tmo;
408                 condlog(3, "%s: update dev_loss_tmo to %d",
409                         mpp->alias, dev_loss_tmo);
410         } else if (mpp->no_path_retry == NO_PATH_RETRY_QUEUE) {
411                 dev_loss_tmo = MAX_DEV_LOSS_TMO;
412                 condlog(3, "%s: update dev_loss_tmo to %d",
413                         mpp->alias, dev_loss_tmo);
414         }
415         mpp->dev_loss = dev_loss_tmo;
416         if (mpp->dev_loss && mpp->fast_io_fail >= (int)mpp->dev_loss) {
417                 condlog(3, "%s: turning off fast_io_fail (%d is not smaller than dev_loss_tmo)",
418                         mpp->alias, mpp->fast_io_fail);
419                 mpp->fast_io_fail = MP_FAST_IO_FAIL_OFF;
420         }
421         if (!mpp->dev_loss && mpp->fast_io_fail == MP_FAST_IO_FAIL_UNSET)
422                 return 0;
423
424         vector_foreach_slot(mpp->paths, pp, i) {
425                 if (pp->sg_id.proto_id == SCSI_PROTOCOL_FCP)
426                         sysfs_set_rport_tmo(mpp, pp);
427                 if (pp->sg_id.proto_id == SCSI_PROTOCOL_ISCSI)
428                         sysfs_set_session_tmo(mpp, pp);
429         }
430         return 0;
431 }
432
433 int
434 do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
435        void *resp, int mx_resp_len)
436 {
437         unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
438                 { INQUIRY_CMD, 0, 0, 0, 0, 0 };
439         unsigned char sense_b[SENSE_BUFF_LEN];
440         struct sg_io_hdr io_hdr;
441
442         if (cmddt)
443                 inqCmdBlk[1] |= 2;
444         if (evpd)
445                 inqCmdBlk[1] |= 1;
446         inqCmdBlk[2] = (unsigned char) pg_op;
447         inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff);
448         inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff);
449         memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
450         memset(sense_b, 0, SENSE_BUFF_LEN);
451         io_hdr.interface_id = 'S';
452         io_hdr.cmd_len = sizeof (inqCmdBlk);
453         io_hdr.mx_sb_len = sizeof (sense_b);
454         io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
455         io_hdr.dxfer_len = mx_resp_len;
456         io_hdr.dxferp = resp;
457         io_hdr.cmdp = inqCmdBlk;
458         io_hdr.sbp = sense_b;
459         io_hdr.timeout = DEF_TIMEOUT;
460
461         if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
462                 return -1;
463
464         /* treat SG_ERR here to get rid of sg_err.[ch] */
465         io_hdr.status &= 0x7e;
466         if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
467             (0 == io_hdr.driver_status))
468                 return 0;
469         if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
470             (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
471             (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
472                 if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
473                         int sense_key;
474                         unsigned char * sense_buffer = io_hdr.sbp;
475                         if (sense_buffer[0] & 0x2)
476                                 sense_key = sense_buffer[1] & 0xf;
477                         else
478                                 sense_key = sense_buffer[2] & 0xf;
479                         if(RECOVERED_ERROR == sense_key)
480                                 return 0;
481                 }
482         }
483         return -1;
484 }
485
486 static int
487 get_serial (char * str, int maxlen, int fd)
488 {
489         int len = 0;
490         char buff[MX_ALLOC_LEN + 1] = {0};
491
492         if (fd < 0)
493                 return 1;
494
495         if (0 == do_inq(fd, 0, 1, 0x80, buff, MX_ALLOC_LEN)) {
496                 len = buff[3];
497                 if (len >= maxlen)
498                         return 1;
499                 if (len > 0) {
500                         memcpy(str, buff + 4, len);
501                         str[len] = '\0';
502                 }
503                 return 0;
504         }
505         return 1;
506 }
507
508 static int
509 get_geometry(struct path *pp)
510 {
511         if (pp->fd < 0)
512                 return 1;
513
514         if (ioctl(pp->fd, HDIO_GETGEO, &pp->geom)) {
515                 condlog(2, "%s: HDIO_GETGEO failed with %d", pp->dev, errno);
516                 memset(&pp->geom, 0, sizeof(pp->geom));
517                 return 1;
518         }
519         condlog(3, "%s: %u cyl, %u heads, %u sectors/track, start at %lu",
520                 pp->dev, pp->geom.cylinders, pp->geom.heads,
521                 pp->geom.sectors, pp->geom.start);
522         return 0;
523 }
524
525 static int
526 scsi_sysfs_pathinfo (struct path * pp)
527 {
528         struct udev_device *parent;
529         const char *attr_path = NULL;
530
531         parent = pp->udev;
532         while (parent) {
533                 const char *subsys = udev_device_get_subsystem(parent);
534                 if (subsys && !strncmp(subsys, "scsi", 4)) {
535                         attr_path = udev_device_get_sysname(parent);
536                         if (!attr_path)
537                                 break;
538                         if (sscanf(attr_path, "%i:%i:%i:%i",
539                                    &pp->sg_id.host_no,
540                                    &pp->sg_id.channel,
541                                    &pp->sg_id.scsi_id,
542                                    &pp->sg_id.lun) == 4)
543                                 break;
544                 }
545                 parent = udev_device_get_parent(parent);
546         }
547         if (!attr_path || pp->sg_id.host_no == -1)
548                 return 1;
549
550         if (sysfs_get_vendor(parent, pp->vendor_id, SCSI_VENDOR_SIZE))
551                 return 1;
552
553         condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
554
555         if (sysfs_get_model(parent, pp->product_id, SCSI_PRODUCT_SIZE))
556                 return 1;
557
558         condlog(3, "%s: product = %s", pp->dev, pp->product_id);
559
560         if (sysfs_get_rev(parent, pp->rev, SCSI_REV_SIZE))
561                 return 1;
562
563         condlog(3, "%s: rev = %s", pp->dev, pp->rev);
564
565         /*
566          * set the hwe configlet pointer
567          */
568         pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, pp->rev);
569
570         /*
571          * host / bus / target / lun
572          */
573         condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
574                         pp->dev,
575                         pp->sg_id.host_no,
576                         pp->sg_id.channel,
577                         pp->sg_id.scsi_id,
578                         pp->sg_id.lun);
579
580         /*
581          * target node name
582          */
583         if(!sysfs_get_tgt_nodename(pp, pp->tgt_node_name)) {
584                 condlog(3, "%s: tgt_node_name = %s",
585                         pp->dev, pp->tgt_node_name);
586         }
587
588         return 0;
589 }
590
591 static int
592 ccw_sysfs_pathinfo (struct path * pp)
593 {
594         struct udev_device *parent;
595         char attr_buff[NAME_SIZE];
596         const char *attr_path;
597
598         parent = pp->udev;
599         while (parent) {
600                 const char *subsys = udev_device_get_subsystem(parent);
601                 if (subsys && !strncmp(subsys, "ccw", 3))
602                         break;
603                 parent = udev_device_get_parent(parent);
604         }
605         if (!parent)
606                 return 1;
607
608         sprintf(pp->vendor_id, "IBM");
609
610         condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
611
612         if (sysfs_get_devtype(parent, attr_buff, FILE_NAME_SIZE))
613                 return 1;
614
615         if (!strncmp(attr_buff, "3370", 4)) {
616                 sprintf(pp->product_id,"S/390 DASD FBA");
617         } else if (!strncmp(attr_buff, "9336", 4)) {
618                 sprintf(pp->product_id,"S/390 DASD FBA");
619         } else {
620                 sprintf(pp->product_id,"S/390 DASD ECKD");
621         }
622
623         condlog(3, "%s: product = %s", pp->dev, pp->product_id);
624
625         /*
626          * set the hwe configlet pointer
627          */
628         pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, NULL);
629
630         /*
631          * host / bus / target / lun
632          */
633         attr_path = udev_device_get_sysname(parent);
634         pp->sg_id.lun = 0;
635         sscanf(attr_path, "%i.%i.%x",
636                         &pp->sg_id.host_no,
637                         &pp->sg_id.channel,
638                         &pp->sg_id.scsi_id);
639         condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
640                         pp->dev,
641                         pp->sg_id.host_no,
642                         pp->sg_id.channel,
643                         pp->sg_id.scsi_id,
644                         pp->sg_id.lun);
645
646         return 0;
647 }
648
649 static int
650 cciss_sysfs_pathinfo (struct path * pp)
651 {
652         const char * attr_path = NULL;
653         struct udev_device *parent;
654
655         parent = pp->udev;
656         while (parent) {
657                 const char *subsys = udev_device_get_subsystem(parent);
658                 if (subsys && !strncmp(subsys, "cciss", 5)) {
659                         attr_path = udev_device_get_sysname(parent);
660                         if (!attr_path)
661                                 break;
662                         if (sscanf(attr_path, "c%id%i",
663                                    &pp->sg_id.host_no,
664                                    &pp->sg_id.scsi_id) == 2)
665                                 break;
666                 }
667                 parent = udev_device_get_parent(parent);
668         }
669         if (!attr_path || pp->sg_id.host_no == -1)
670                 return 1;
671
672         if (sysfs_get_vendor(parent, pp->vendor_id, SCSI_VENDOR_SIZE))
673                 return 1;
674
675         condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
676
677         if (sysfs_get_model(parent, pp->product_id, SCSI_PRODUCT_SIZE))
678                 return 1;
679
680         condlog(3, "%s: product = %s", pp->dev, pp->product_id);
681
682         if (sysfs_get_rev(parent, pp->rev, SCSI_REV_SIZE))
683                 return 1;
684
685         condlog(3, "%s: rev = %s", pp->dev, pp->rev);
686
687         /*
688          * set the hwe configlet pointer
689          */
690         pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, pp->rev);
691
692         /*
693          * host / bus / target / lun
694          */
695         pp->sg_id.lun = 0;
696         pp->sg_id.channel = 0;
697         condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
698                 pp->dev,
699                 pp->sg_id.host_no,
700                 pp->sg_id.channel,
701                 pp->sg_id.scsi_id,
702                 pp->sg_id.lun);
703         return 0;
704 }
705
706 static int
707 common_sysfs_pathinfo (struct path * pp)
708 {
709         if (!pp->udev) {
710                 condlog(4, "%s: udev not initialised", pp->dev);
711                 return 1;
712         }
713         if (sysfs_get_dev(pp->udev, pp->dev_t, BLK_DEV_SIZE)) {
714                 condlog(3, "%s: no 'dev' attribute in sysfs", pp->dev);
715                 return 1;
716         }
717
718         condlog(3, "%s: dev_t = %s", pp->dev, pp->dev_t);
719
720         if (sysfs_get_size(pp, &pp->size))
721                 return 1;
722
723         condlog(3, "%s: size = %llu", pp->dev, pp->size);
724
725         return 0;
726 }
727
728 int
729 path_offline (struct path * pp)
730 {
731         struct udev_device * parent;
732         char buff[SCSI_STATE_SIZE];
733
734         if (pp->bus != SYSFS_BUS_SCSI)
735                 return PATH_UP;
736
737         parent = pp->udev;
738         while (parent) {
739                 const char *subsys = udev_device_get_subsystem(parent);
740                 if (subsys && !strncmp(subsys, "scsi", 4))
741                         break;
742                 parent = udev_device_get_parent(parent);
743         }
744
745         if (!parent) {
746                 condlog(1, "%s: failed to get sysfs information", pp->dev);
747                 return PATH_DOWN;
748         }
749
750         if (sysfs_get_state(parent, buff, SCSI_STATE_SIZE))
751                 return PATH_DOWN;
752
753         condlog(3, "%s: path state = %s", pp->dev, buff);
754
755         if (!strncmp(buff, "offline", 7)) {
756                 pp->offline = 1;
757                 return PATH_DOWN;
758         }
759         pp->offline = 0;
760         if (!strncmp(buff, "blocked", 7))
761                 return PATH_PENDING;
762         else if (!strncmp(buff, "running", 7))
763                 return PATH_UP;
764
765         return PATH_DOWN;
766 }
767
768 int
769 sysfs_pathinfo(struct path * pp)
770 {
771         if (common_sysfs_pathinfo(pp))
772                 return 1;
773
774         pp->bus = SYSFS_BUS_UNDEF;
775         if (!strncmp(pp->dev,"cciss",5))
776                 pp->bus = SYSFS_BUS_CCISS;
777         if (!strncmp(pp->dev,"dasd", 4))
778                 pp->bus = SYSFS_BUS_CCW;
779         if (!strncmp(pp->dev,"sd", 2))
780                 pp->bus = SYSFS_BUS_SCSI;
781
782         if (pp->bus == SYSFS_BUS_UNDEF)
783                 return 0;
784         else if (pp->bus == SYSFS_BUS_SCSI) {
785                 if (scsi_sysfs_pathinfo(pp))
786                         return 1;
787         } else if (pp->bus == SYSFS_BUS_CCW) {
788                 if (ccw_sysfs_pathinfo(pp))
789                         return 1;
790         } else if (pp->bus == SYSFS_BUS_CCISS) {
791                 if (cciss_sysfs_pathinfo(pp))
792                         return 1;
793         }
794         return 0;
795 }
796
797 static int
798 scsi_ioctl_pathinfo (struct path * pp, int mask)
799 {
800         if (mask & DI_SERIAL) {
801                 get_serial(pp->serial, SERIAL_SIZE, pp->fd);
802                 condlog(3, "%s: serial = %s", pp->dev, pp->serial);
803         }
804
805         return 0;
806 }
807
808 static int
809 cciss_ioctl_pathinfo (struct path * pp, int mask)
810 {
811         if (mask & DI_SERIAL) {
812                 get_serial(pp->serial, SERIAL_SIZE, pp->fd);
813                 condlog(3, "%s: serial = %s", pp->dev, pp->serial);
814         }
815         return 0;
816 }
817
818 int
819 get_state (struct path * pp, int daemon)
820 {
821         struct checker * c = &pp->checker;
822         int state;
823
824         condlog(3, "%s: get_state", pp->dev);
825
826         if (!checker_selected(c)) {
827                 if (daemon) {
828                         if (pathinfo(pp, conf->hwtable, DI_SYSFS) != 0) {
829                                 condlog(3, "%s: couldn't get sysfs pathinfo",
830                                         pp->dev);
831                                 return PATH_UNCHECKED;
832                         }
833                 }
834                 select_checker(pp);
835                 if (!checker_selected(c)) {
836                         condlog(3, "%s: No checker selected", pp->dev);
837                         return PATH_UNCHECKED;
838                 }
839                 checker_set_fd(c, pp->fd);
840                 if (checker_init(c, pp->mpp?&pp->mpp->mpcontext:NULL)) {
841                         memset(c, 0x0, sizeof(struct checker));
842                         condlog(3, "%s: checker init failed", pp->dev);
843                         return PATH_UNCHECKED;
844                 }
845         }
846         checker_clear_message(c);
847         if (daemon)
848                 checker_set_async(c);
849         if (!conf->checker_timeout &&
850             (pp->bus != SYSFS_BUS_SCSI ||
851              sysfs_get_timeout(pp, &(c->timeout))))
852                 c->timeout = DEF_TIMEOUT;
853         state = checker_check(c);
854         condlog(3, "%s: state = %s", pp->dev, checker_state_name(state));
855         if (state != PATH_UP && strlen(checker_message(c)))
856                 condlog(3, "%s: checker msg is \"%s\"",
857                         pp->dev, checker_message(c));
858         return state;
859 }
860
861 static int
862 get_prio (struct path * pp)
863 {
864         if (!pp)
865                 return 0;
866
867         struct prio * p = &pp->prio;
868
869         if (!prio_selected(p)) {
870                 select_detect_prio(pp);
871                 select_prio(pp);
872                 if (!prio_selected(p)) {
873                         condlog(3, "%s: no prio selected", pp->dev);
874                         return 1;
875                 }
876         }
877         pp->priority = prio_getprio(p, pp);
878         if (pp->priority < 0) {
879                 condlog(3, "%s: %s prio error", pp->dev, prio_name(p));
880                 pp->priority = PRIO_UNDEF;
881                 return 1;
882         }
883         condlog(3, "%s: %s prio = %u",
884                 pp->dev, prio_name(p), pp->priority);
885         return 0;
886 }
887
888 static int
889 get_uid (struct path * pp)
890 {
891         char *c;
892         const char *value;
893
894         if (!pp->uid_attribute)
895                 select_getuid(pp);
896
897         if (!pp->udev) {
898                 condlog(1, "%s: no udev information", pp->dev);
899                 return 1;
900         }
901
902         memset(pp->wwid, 0, WWID_SIZE);
903         value = udev_device_get_property_value(pp->udev, pp->uid_attribute);
904         if ((!value || strlen(value) == 0) && conf->dry_run == 2)
905                 value = getenv(pp->uid_attribute);
906         if (value && strlen(value)) {
907                 size_t len = WWID_SIZE;
908
909                 if (strlen(value) + 1 > WWID_SIZE) {
910                         condlog(0, "%s: wwid overflow", pp->dev);
911                 } else {
912                         len = strlen(value);
913                 }
914                 strncpy(pp->wwid, value, len);
915         } else {
916                 condlog(3, "%s: no %s attribute", pp->dev,
917                         pp->uid_attribute);
918         }
919
920         /* Strip any trailing blanks */
921         c = strchr(pp->wwid, '\0');
922         c--;
923         while (c && c >= pp->wwid && *c == ' ') {
924                 *c = '\0';
925                 c--;
926         }
927         condlog(3, "%s: uid = %s (udev)", pp->dev,
928                 *pp->wwid == '\0' ? "<empty>" : pp->wwid);
929         return 0;
930 }
931
932 extern int
933 pathinfo (struct path *pp, vector hwtable, int mask)
934 {
935         int path_state;
936
937         condlog(3, "%s: mask = 0x%x", pp->dev, mask);
938
939         /*
940          * fetch info available in sysfs
941          */
942         if (mask & DI_SYSFS && sysfs_pathinfo(pp))
943                 return 1;
944
945         if (mask & DI_BLACKLIST && mask & DI_SYSFS) {
946                 if (filter_device(conf->blist_device, conf->elist_device,
947                                   pp->vendor_id, pp->product_id) > 0) {
948                         return 2;
949                 }
950         }
951
952         path_state = path_offline(pp);
953
954         /*
955          * fetch info not available through sysfs
956          */
957         if (pp->fd < 0)
958                 pp->fd = open(udev_device_get_devnode(pp->udev), O_RDONLY);
959
960         if (pp->fd < 0) {
961                 condlog(4, "Couldn't open node for %s: %s",
962                         pp->dev, strerror(errno));
963                 goto blank;
964         }
965
966         if (mask & DI_SERIAL)
967                 get_geometry(pp);
968
969         if (path_state == PATH_UP && pp->bus == SYSFS_BUS_SCSI &&
970             scsi_ioctl_pathinfo(pp, mask))
971                 goto blank;
972
973         if (pp->bus == SYSFS_BUS_CCISS &&
974             cciss_ioctl_pathinfo(pp, mask))
975                 goto blank;
976
977         if (mask & DI_CHECKER) {
978                 if (path_state == PATH_UP) {
979                         pp->chkrstate = pp->state = get_state(pp, 0);
980                         if (pp->state == PATH_UNCHECKED ||
981                             pp->state == PATH_WILD)
982                                 goto blank;
983                 } else {
984                         condlog(3, "%s: path inaccessible", pp->dev);
985                         pp->chkrstate = pp->state = path_state;
986                 }
987         }
988
989         if (path_state == PATH_UP && (mask & DI_WWID) && !strlen(pp->wwid))
990                 get_uid(pp);
991         if (mask & DI_BLACKLIST && mask & DI_WWID) {
992                 if (filter_wwid(conf->blist_wwid, conf->elist_wwid,
993                                 pp->wwid) > 0) {
994                         return 2;
995                 }
996         }
997
998          /*
999           * Retrieve path priority, even for PATH_DOWN paths if it has never
1000           * been successfully obtained before.
1001           */
1002         if ((mask & DI_PRIO) && path_state == PATH_UP) {
1003                 if (pp->state != PATH_DOWN || pp->priority == PRIO_UNDEF) {
1004                         if (!strlen(pp->wwid))
1005                                 get_uid(pp);
1006                         get_prio(pp);
1007                 } else {
1008                         pp->priority = PRIO_UNDEF;
1009                 }
1010         }
1011
1012         return 0;
1013
1014 blank:
1015         /*
1016          * Recoverable error, for example faulty or offline path
1017          */
1018         memset(pp->wwid, 0, WWID_SIZE);
1019         pp->chkrstate = pp->state = PATH_DOWN;
1020
1021         return 0;
1022 }