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