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