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