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