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