Remove sysfs_attr cache
[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         io_hdr.interface_id = 'S';
350         io_hdr.cmd_len = sizeof (inqCmdBlk);
351         io_hdr.mx_sb_len = sizeof (sense_b);
352         io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
353         io_hdr.dxfer_len = mx_resp_len;
354         io_hdr.dxferp = resp;
355         io_hdr.cmdp = inqCmdBlk;
356         io_hdr.sbp = sense_b;
357         io_hdr.timeout = DEF_TIMEOUT;
358
359         if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
360                 return -1;
361
362         /* treat SG_ERR here to get rid of sg_err.[ch] */
363         io_hdr.status &= 0x7e;
364         if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
365             (0 == io_hdr.driver_status))
366                 return 0;
367         if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
368             (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
369             (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
370                 if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
371                         int sense_key;
372                         unsigned char * sense_buffer = io_hdr.sbp;
373                         if (sense_buffer[0] & 0x2)
374                                 sense_key = sense_buffer[1] & 0xf;
375                         else
376                                 sense_key = sense_buffer[2] & 0xf;
377                         if(RECOVERED_ERROR == sense_key)
378                                 return 0;
379                 }
380         }
381         return -1;
382 }
383
384 static int
385 get_serial (char * str, int maxlen, int fd)
386 {
387         int len = 0;
388         char buff[MX_ALLOC_LEN + 1] = {0};
389
390         if (fd < 0)
391                 return 1;
392
393         if (0 == do_inq(fd, 0, 1, 0x80, buff, MX_ALLOC_LEN)) {
394                 len = buff[3];
395                 if (len >= maxlen)
396                         return 1;
397                 if (len > 0) {
398                         memcpy(str, buff + 4, len);
399                         str[len] = '\0';
400                 }
401                 return 0;
402         }
403         return 1;
404 }
405
406 static int
407 get_inq (char * dev, char * vendor, char * product, char * rev, int fd)
408 {
409         unsigned char buff[MX_ALLOC_LEN + 1] = {0};
410         int len;
411
412         if (fd < 0)
413                 return 1;
414
415         if (0 != do_inq(fd, 0, 0, 0, buff, MX_ALLOC_LEN))
416                 return 1;
417
418         /* Check peripheral qualifier */
419         if ((buff[0] >> 5) != 0) {
420                 int pqual = (buff[0] >> 5);
421                 switch (pqual) {
422                 case 1:
423                         condlog(3, "%s: INQUIRY failed, LU not connected", dev);
424                         break;
425                 case 3:
426                         condlog(3, "%s: INQUIRY failed, LU not supported", dev);
427                         break;
428                 default:
429                         condlog(3, "%s: INQUIRY failed, Invalid PQ %x",
430                                 dev, pqual);
431                         break;
432                 }
433
434                 return 1;
435         }
436
437         len = buff[4] + 4;
438
439         if (len < 8) {
440                 condlog(3, "%s: INQUIRY response too short (len %d)",
441                         dev, len);
442                 return 1;
443         }
444
445         len -= 8;
446         memset(vendor, 0x0, 8);
447         memcpy(vendor, buff + 8, len > 8 ? 8 : len);
448         vendor[8] = '\0';
449         strchop(vendor);
450         if (len <= 8)
451                 return 0;
452
453         len -= 8;
454
455         memset(product, 0x0, 16);
456         memcpy(product, buff + 16, len > 16 ? 16 : len);
457         product[16] = '\0';
458         strchop(product);
459         if (len <= 16)
460                 return 0;
461
462         len -= 16;
463
464         memset(rev, 0x0, 4);
465         memcpy(rev, buff + 32, 4);
466         rev[4] = '\0';
467         strchop(rev);
468
469         return 0;
470 }
471
472 static int
473 get_geometry(struct path *pp)
474 {
475         if (pp->fd < 0)
476                 return 1;
477
478         if (ioctl(pp->fd, HDIO_GETGEO, &pp->geom)) {
479                 condlog(2, "%s: HDIO_GETGEO failed with %d", pp->dev, errno);
480                 memset(&pp->geom, 0, sizeof(pp->geom));
481                 return 1;
482         }
483         condlog(3, "%s: %u cyl, %u heads, %u sectors/track, start at %lu",
484                 pp->dev, pp->geom.cylinders, pp->geom.heads,
485                 pp->geom.sectors, pp->geom.start);
486         return 0;
487 }
488
489 static int
490 scsi_sysfs_pathinfo (struct path * pp, struct sysfs_device * parent)
491 {
492         char attr_path[FILE_NAME_SIZE];
493
494         if (sysfs_get_vendor(parent, pp->vendor_id, SCSI_VENDOR_SIZE))
495                 return 1;
496
497         condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
498
499         if (sysfs_get_model(parent, pp->product_id, SCSI_PRODUCT_SIZE))
500                 return 1;
501
502         condlog(3, "%s: product = %s", pp->dev, pp->product_id);
503
504         if (sysfs_get_rev(parent, pp->rev, SCSI_REV_SIZE))
505                 return 1;
506
507         condlog(3, "%s: rev = %s", pp->dev, pp->rev);
508
509         /*
510          * set the hwe configlet pointer
511          */
512         pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, pp->rev);
513
514         /*
515          * host / bus / target / lun
516          */
517         basenamecpy(parent->devpath, attr_path, FILE_NAME_SIZE);
518
519         sscanf(attr_path, "%i:%i:%i:%i",
520                         &pp->sg_id.host_no,
521                         &pp->sg_id.channel,
522                         &pp->sg_id.scsi_id,
523                         &pp->sg_id.lun);
524         condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
525                         pp->dev,
526                         pp->sg_id.host_no,
527                         pp->sg_id.channel,
528                         pp->sg_id.scsi_id,
529                         pp->sg_id.lun);
530
531         /*
532          * target node name
533          */
534         if(!sysfs_get_fc_nodename(parent, pp->tgt_node_name,
535                                  pp->sg_id.host_no,
536                                  pp->sg_id.channel,
537                                  pp->sg_id.scsi_id)) {
538                 condlog(3, "%s: tgt_node_name = %s",
539                         pp->dev, pp->tgt_node_name);
540         }
541
542         return 0;
543 }
544
545 static int
546 ccw_sysfs_pathinfo (struct path * pp, struct sysfs_device * parent)
547 {
548         char attr_path[FILE_NAME_SIZE];
549         char attr_buff[FILE_NAME_SIZE];
550
551         sprintf(pp->vendor_id, "IBM");
552
553         condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
554
555         if (sysfs_get_devtype(parent, attr_buff, FILE_NAME_SIZE))
556                 return 1;
557
558         if (!strncmp(attr_buff, "3370", 4)) {
559                 sprintf(pp->product_id,"S/390 DASD FBA");
560         } else if (!strncmp(attr_buff, "9336", 4)) {
561                 sprintf(pp->product_id,"S/390 DASD FBA");
562         } else {
563                 sprintf(pp->product_id,"S/390 DASD ECKD");
564         }
565
566         condlog(3, "%s: product = %s", pp->dev, pp->product_id);
567
568         /*
569          * set the hwe configlet pointer
570          */
571         pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, NULL);
572
573         /*
574          * host / bus / target / lun
575          */
576         basenamecpy(parent->devpath, attr_path, FILE_NAME_SIZE);
577         pp->sg_id.lun = 0;
578         sscanf(attr_path, "%i.%i.%x",
579                         &pp->sg_id.host_no,
580                         &pp->sg_id.channel,
581                         &pp->sg_id.scsi_id);
582         condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
583                         pp->dev,
584                         pp->sg_id.host_no,
585                         pp->sg_id.channel,
586                         pp->sg_id.scsi_id,
587                         pp->sg_id.lun);
588
589         return 0;
590 }
591
592 static int
593 cciss_sysfs_pathinfo (struct path * pp, struct sysfs_device * dev)
594 {
595         char attr_path[FILE_NAME_SIZE];
596
597         /*
598          * host / bus / target / lun
599          */
600         basenamecpy(dev->devpath, attr_path, FILE_NAME_SIZE);
601         pp->sg_id.lun = 0;
602         pp->sg_id.channel = 0;
603         sscanf(attr_path, "cciss!c%id%i",
604                         &pp->sg_id.host_no,
605                         &pp->sg_id.scsi_id);
606         condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
607                         pp->dev,
608                         pp->sg_id.host_no,
609                         pp->sg_id.channel,
610                         pp->sg_id.scsi_id,
611                         pp->sg_id.lun);
612         return 0;
613 }
614
615 static int
616 common_sysfs_pathinfo (struct path * pp, struct sysfs_device *dev)
617 {
618         size_t len;
619
620         len = sysfs_attr_get_value(dev->devpath, "dev",
621                                     pp->dev_t, BLK_DEV_SIZE);
622         if (!len) {
623                 condlog(3, "%s: no 'dev' attribute in sysfs", pp->dev);
624                 return 1;
625         }
626
627         condlog(3, "%s: dev_t = %s", pp->dev, pp->dev_t);
628
629         if (sysfs_get_size(dev, &pp->size))
630                 return 1;
631
632         condlog(3, "%s: size = %llu", pp->dev, pp->size);
633
634         return 0;
635 }
636
637 struct sysfs_device *sysfs_device_from_path(struct path *pp)
638 {
639         char sysdev[FILE_NAME_SIZE];
640
641         strlcpy(sysdev,"/block/", FILE_NAME_SIZE);
642         strlcat(sysdev,pp->dev, FILE_NAME_SIZE);
643
644         return sysfs_device_get(sysdev);
645 }
646
647 int
648 path_offline (struct path * pp)
649 {
650         struct sysfs_device * parent;
651         char buff[SCSI_STATE_SIZE];
652
653         pp->sysdev = sysfs_device_from_path(pp);
654         if (!pp->sysdev) {
655                 condlog(1, "%s: failed to get sysfs information", pp->dev);
656                 return PATH_WILD;
657         }
658
659         parent = sysfs_device_get_parent(pp->sysdev);
660         if (!parent)
661                 parent = pp->sysdev;
662         if (parent && !strncmp(parent->kernel, "block",5))
663                 parent = sysfs_device_get_parent(parent);
664         if (!parent) {
665                 condlog(1, "%s: failed to get parent", pp->dev);
666                 return PATH_WILD;
667         }
668
669         if (sysfs_get_state(parent, buff, SCSI_STATE_SIZE))
670                 return PATH_WILD;
671
672         condlog(3, "%s: state = %s", pp->dev, buff);
673
674         if (!strncmp(buff, "offline", 7)) {
675                 pp->offline = 1;
676                 return PATH_DOWN;
677         }
678         pp->offline = 0;
679         if (!strncmp(buff, "blocked", 7))
680                 return PATH_PENDING;
681         else if (!strncmp(buff, "running", 7))
682                 return PATH_UP;
683
684         return PATH_DOWN;
685 }
686
687 extern int
688 sysfs_pathinfo(struct path * pp)
689 {
690         struct sysfs_device *parent;
691
692         pp->sysdev = sysfs_device_from_path(pp);
693         if (!pp->sysdev) {
694                 condlog(1, "%s: failed to get sysfs information", pp->dev);
695                 return 1;
696         }
697
698         if (common_sysfs_pathinfo(pp, pp->sysdev))
699                 return 1;
700
701         parent = sysfs_device_get_parent(pp->sysdev);
702         if (!parent)
703                 parent = pp->sysdev;
704         if (parent && !strncmp(parent->kernel, "block",5))
705                 parent = sysfs_device_get_parent(parent);
706         if (!parent) {
707                 condlog(1, "%s: failed to get parent", pp->dev);
708                 return 1;
709         }
710
711         if (!strncmp(pp->dev,"cciss",5))
712                 strcpy(parent->subsystem,"cciss");
713
714         condlog(3, "%s: subsystem = %s", pp->dev, parent->subsystem);
715
716         if (!strncmp(parent->subsystem, "scsi",4))
717                 pp->bus = SYSFS_BUS_SCSI;
718         if (!strncmp(parent->subsystem, "ccw",3))
719                 pp->bus = SYSFS_BUS_CCW;
720         if (!strncmp(parent->subsystem,"cciss",5))
721                 pp->bus = SYSFS_BUS_CCISS;
722
723         if (pp->bus == SYSFS_BUS_UNDEF)
724                 return 0;
725         else if (pp->bus == SYSFS_BUS_SCSI) {
726                 if (scsi_sysfs_pathinfo(pp, parent))
727                         return 1;
728         } else if (pp->bus == SYSFS_BUS_CCW) {
729                 if (ccw_sysfs_pathinfo(pp, parent))
730                         return 1;
731         } else if (pp->bus == SYSFS_BUS_CCISS) {
732                 if (cciss_sysfs_pathinfo(pp, pp->sysdev))
733                         return 1;
734         }
735         return 0;
736 }
737
738 static int
739 scsi_ioctl_pathinfo (struct path * pp, int mask)
740 {
741         if (mask & DI_SERIAL) {
742                 get_serial(pp->serial, SERIAL_SIZE, pp->fd);
743                 condlog(3, "%s: serial = %s", pp->dev, pp->serial);
744         }
745
746         return 0;
747 }
748
749 static int
750 cciss_ioctl_pathinfo (struct path * pp, int mask)
751 {
752         int ret;
753
754         if (mask & DI_SYSFS) {
755                 ret = get_inq(pp->dev, pp->vendor_id, pp->product_id,
756                               pp->rev, pp->fd);
757                 if (ret)
758                         return ret;
759
760                 condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
761                 condlog(3, "%s: product = %s", pp->dev, pp->product_id);
762                 condlog(3, "%s: revision = %s", pp->dev, pp->rev);
763                 /*
764                  * set the hwe configlet pointer
765                  */
766                 pp->hwe = find_hwe(conf->hwtable, pp->vendor_id,
767                                    pp->product_id, pp->rev);
768
769         }
770         return 0;
771 }
772
773 int
774 get_state (struct path * pp, int daemon)
775 {
776         struct checker * c = &pp->checker;
777         int state;
778
779         condlog(3, "%s: get_state", pp->dev);
780
781         if (!checker_selected(c)) {
782                 if (daemon)
783                         pathinfo(pp, conf->hwtable, DI_SYSFS);
784                 select_checker(pp);
785                 if (!checker_selected(c)) {
786                         condlog(3, "%s: No checker selected", pp->dev);
787                         return PATH_UNCHECKED;
788                 }
789                 checker_set_fd(c, pp->fd);
790                 if (checker_init(c, pp->mpp?&pp->mpp->mpcontext:NULL)) {
791                         condlog(3, "%s: checker init failed", pp->dev);
792                         return PATH_UNCHECKED;
793                 }
794         }
795         checker_clear_message(c);
796         state = path_offline(pp);
797         if (state != PATH_UP) {
798                 condlog(3, "%s: path inaccessible", pp->dev);
799                 return state;
800         }
801         if (daemon)
802                 checker_set_async(c);
803         if (!conf->checker_timeout)
804                 sysfs_get_timeout(pp->sysdev, &(c->timeout));
805         state = checker_check(c);
806         condlog(3, "%s: state = %i", pp->dev, state);
807         if (state == PATH_DOWN && strlen(checker_message(c)))
808                 condlog(3, "%s: checker msg is \"%s\"",
809                         pp->dev, checker_message(c));
810         return state;
811 }
812
813 static int
814 get_prio (struct path * pp)
815 {
816         if (!pp)
817                 return 0;
818
819         if (!pp->prio) {
820                 select_prio(pp);
821                 if (!pp->prio) {
822                         condlog(3, "%s: no prio selected", pp->dev);
823                         return 1;
824                 }
825         }
826         pp->priority = prio_getprio(pp->prio, pp);
827         if (pp->priority < 0) {
828                 condlog(3, "%s: %s prio error", pp->dev, prio_name(pp->prio));
829                 pp->priority = PRIO_UNDEF;
830                 return 1;
831         }
832         condlog(3, "%s: %s prio = %u",
833                 pp->dev, prio_name(pp->prio), pp->priority);
834         return 0;
835 }
836
837 static int
838 get_uid (struct path * pp)
839 {
840         char buff[CALLOUT_MAX_SIZE], *c;
841
842         if (!pp->getuid)
843                 select_getuid(pp);
844
845         if (apply_format(pp->getuid, &buff[0], pp)) {
846                 condlog(0, "error formatting uid callout command");
847                 memset(pp->wwid, 0, WWID_SIZE);
848         } else if (execute_program(buff, pp->wwid, WWID_SIZE)) {
849                 condlog(3, "error calling out %s", buff);
850                 memset(pp->wwid, 0, WWID_SIZE);
851                 return 1;
852         }
853         /* Strip any trailing blanks */
854         c = strchr(pp->wwid, '\0');
855         c--;
856         while (c && c >= pp->wwid && *c == ' ') {
857                 *c = '\0';
858                 c--;
859         }
860         condlog(3, "%s: uid = %s (callout)", pp->dev,
861                 *pp->wwid == '\0' ? "<empty>" : pp->wwid);
862         return 0;
863 }
864
865 extern int
866 pathinfo (struct path *pp, vector hwtable, int mask)
867 {
868         condlog(3, "%s: mask = 0x%x", pp->dev, mask);
869
870         /*
871          * fetch info available in sysfs
872          */
873         if (mask & DI_SYSFS && sysfs_pathinfo(pp))
874                 return 1;
875
876         /*
877          * fetch info not available through sysfs
878          */
879         if (pp->fd < 0)
880                 pp->fd = opennode(pp->dev, O_RDONLY);
881
882         if (pp->fd < 0) {
883                 condlog(4, "Couldn't open node for %s: %s",
884                         pp->dev, strerror(errno));
885                 goto blank;
886         }
887
888         if (mask & DI_SERIAL)
889                 get_geometry(pp);
890
891         if (pp->bus == SYSFS_BUS_SCSI &&
892             scsi_ioctl_pathinfo(pp, mask))
893                 goto blank;
894
895         if (pp->bus == SYSFS_BUS_CCISS &&
896             cciss_ioctl_pathinfo(pp, mask))
897                 goto blank;
898
899         if (mask & DI_CHECKER) {
900                 pp->state = get_state(pp, 0);
901                 if (pp->state == PATH_UNCHECKED || pp->state == PATH_WILD)
902                         goto blank;
903         }
904
905          /*
906           * Retrieve path priority, even for PATH_DOWN paths if it has never
907           * been successfully obtained before.
908           */
909         if (mask & DI_PRIO &&
910             (pp->state != PATH_DOWN || pp->priority == PRIO_UNDEF)) {
911                 if (!strlen(pp->wwid))
912                         get_uid(pp);
913                 get_prio(pp);
914         }
915
916         if (mask & DI_WWID && !strlen(pp->wwid))
917                 get_uid(pp);
918
919         return 0;
920
921 blank:
922         /*
923          * Recoverable error, for example faulty or offline path
924          */
925         memset(pp->wwid, 0, WWID_SIZE);
926         pp->state = PATH_DOWN;
927
928         return 0;
929 }