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