899cbd5548274360ed0b795ed235755821a22188
[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 <ctype.h>
8 #include <unistd.h>
9 #include <fcntl.h>
10 #include <sys/ioctl.h>
11 #include <sys/stat.h>
12 #include <dirent.h>
13 #include <errno.h>
14 #include <libgen.h>
15 #include <libudev.h>
16
17 #include "checkers.h"
18 #include "vector.h"
19 #include "memory.h"
20 #include "util.h"
21 #include "structs.h"
22 #include "config.h"
23 #include "blacklist.h"
24 #include "callout.h"
25 #include "debug.h"
26 #include "propsel.h"
27 #include "sg_include.h"
28 #include "sysfs.h"
29 #include "discovery.h"
30 #include "prio.h"
31 #include "defaults.h"
32
33 int
34 store_pathinfo (vector pathvec, vector hwtable, struct udev_device *udevice,
35                 int flag, struct path **pp_ptr)
36 {
37         int err = PATHINFO_FAILED;
38         struct path * pp;
39         const char * devname;
40
41         if (pp_ptr)
42                 *pp_ptr = NULL;
43
44         devname = udev_device_get_sysname(udevice);
45         if (!devname)
46                 return PATHINFO_FAILED;
47
48         pp = alloc_path();
49
50         if (!pp)
51                 return PATHINFO_FAILED;
52
53         if(safe_sprintf(pp->dev, "%s", devname)) {
54                 condlog(0, "pp->dev too small");
55                 goto out;
56         }
57         pp->udev = udev_device_ref(udevice);
58         err = pathinfo(pp, hwtable,
59                        (conf->cmd == CMD_REMOVE_WWID)? flag :
60                                                        (flag | DI_BLACKLIST));
61         if (err)
62                 goto out;
63
64         err = store_path(pathvec, pp);
65         if (err)
66                 goto out;
67
68 out:
69         if (err)
70                 free_path(pp);
71         else if (pp_ptr)
72                 *pp_ptr = pp;
73         return err;
74 }
75
76 static int
77 path_discover (vector pathvec, struct config * conf,
78                struct udev_device *udevice, int flag)
79 {
80         struct path * pp;
81         const char * devname;
82
83         devname = udev_device_get_sysname(udevice);
84         if (!devname)
85                 return PATHINFO_FAILED;
86
87         if (filter_property(conf, udevice) > 0)
88                 return PATHINFO_SKIPPED;
89
90         if (filter_devnode(conf->blist_devnode, conf->elist_devnode,
91                            (char *)devname) > 0)
92                 return PATHINFO_SKIPPED;
93
94         pp = find_path_by_dev(pathvec, (char *)devname);
95         if (!pp) {
96                 return store_pathinfo(pathvec, conf->hwtable,
97                                       udevice, flag, NULL);
98         }
99         return pathinfo(pp, conf->hwtable, flag);
100 }
101
102 int
103 path_discovery (vector pathvec, struct config * conf, int flag)
104 {
105         struct udev_enumerate *udev_iter;
106         struct udev_list_entry *entry;
107         struct udev_device *udevice;
108         const char *devpath;
109         int num_paths = 0, total_paths = 0;
110
111         udev_iter = udev_enumerate_new(conf->udev);
112         if (!udev_iter)
113                 return -ENOMEM;
114
115         udev_enumerate_add_match_subsystem(udev_iter, "block");
116         udev_enumerate_scan_devices(udev_iter);
117
118         udev_list_entry_foreach(entry,
119                                 udev_enumerate_get_list_entry(udev_iter)) {
120                 const char *devtype;
121                 devpath = udev_list_entry_get_name(entry);
122                 condlog(4, "Discover device %s", devpath);
123                 udevice = udev_device_new_from_syspath(conf->udev, devpath);
124                 if (!udevice) {
125                         condlog(4, "%s: no udev information", devpath);
126                         continue;
127                 }
128                 devtype = udev_device_get_devtype(udevice);
129                 if(devtype && !strncmp(devtype, "disk", 4)) {
130                         total_paths++;
131                         if (path_discover(pathvec, conf,
132                                           udevice, flag) == PATHINFO_OK)
133                                 num_paths++;
134                 }
135                 udev_device_unref(udevice);
136         }
137         udev_enumerate_unref(udev_iter);
138         condlog(4, "Discovered %d/%d paths", num_paths, total_paths);
139         return (total_paths - num_paths);
140 }
141
142 #define declare_sysfs_get_str(fname)                                    \
143 extern ssize_t                                                          \
144 sysfs_get_##fname (struct udev_device * udev, char * buff, size_t len)  \
145 {                                                                       \
146         int l;                                                  \
147         const char * attr;                                              \
148         const char * devname;                                           \
149                                                                         \
150         if (!udev)                                                      \
151                 return -ENOSYS;                                         \
152                                                                         \
153         devname = udev_device_get_sysname(udev);                        \
154                                                                         \
155         attr = udev_device_get_sysattr_value(udev, #fname);             \
156         if (!attr) {                                                    \
157                 condlog(3, "%s: attribute %s not found in sysfs",       \
158                         devname, #fname);                               \
159                 return -ENXIO;                                          \
160         }                                                               \
161         for (l = strlen(attr); l >= 1 && isspace(attr[l-1]); l--);      \
162         if (l > len) {                                                  \
163                 condlog(3, "%s: overflow in attribute %s",              \
164                         devname, #fname);                               \
165                 return -EINVAL;                                         \
166         }                                                               \
167         strlcpy(buff, attr, len);                                       \
168         return strchop(buff);                                           \
169 }
170
171 declare_sysfs_get_str(devtype);
172 declare_sysfs_get_str(vendor);
173 declare_sysfs_get_str(model);
174 declare_sysfs_get_str(rev);
175 declare_sysfs_get_str(dev);
176
177 int
178 sysfs_get_timeout(struct path *pp, unsigned int *timeout)
179 {
180         const char *attr = NULL;
181         const char *subsys;
182         struct udev_device *parent;
183         int r;
184         unsigned int t;
185
186         if (!pp->udev || pp->bus != SYSFS_BUS_SCSI)
187                 return -ENOSYS;
188
189         parent = pp->udev;
190         while (parent) {
191                 subsys = udev_device_get_subsystem(parent);
192                 attr = udev_device_get_sysattr_value(parent, "timeout");
193                 if (subsys && attr)
194                         break;
195                 parent = udev_device_get_parent(parent);
196         }
197         if (!attr) {
198                 condlog(3, "%s: No timeout value in sysfs", pp->dev);
199                 return -ENXIO;
200         }
201
202         r = sscanf(attr, "%u\n", &t);
203
204         if (r != 1) {
205                 condlog(3, "%s: Cannot parse timeout attribute '%s'",
206                         pp->dev, attr);
207                 return -EINVAL;
208         }
209
210         *timeout = t;
211
212         return 0;
213 }
214
215 int
216 sysfs_get_tgt_nodename (struct path *pp, char * node)
217 {
218         const char *tgtname, *value;
219         struct udev_device *parent, *tgtdev;
220         int host, channel, tgtid = -1;
221
222         parent = udev_device_get_parent_with_subsystem_devtype(pp->udev, "scsi", "scsi_device");
223         if (!parent)
224                 return 1;
225         /* Check for SAS */
226         value = udev_device_get_sysattr_value(parent, "sas_address");
227         if (value) {
228                 tgtdev = udev_device_get_parent(parent);
229                 while (tgtdev) {
230                         tgtname = udev_device_get_sysname(tgtdev);
231                         if (sscanf(tgtname, "end_device-%d:%d",
232                                    &host, &tgtid) == 2)
233                                 break;
234                         tgtdev = udev_device_get_parent(tgtdev);
235                         tgtid = -1;
236                 }
237                 if (tgtid >= 0) {
238                         pp->sg_id.proto_id = SCSI_PROTOCOL_SAS;
239                         pp->sg_id.transport_id = tgtid;
240                         strncpy(node, value, NODE_NAME_SIZE);
241                         return 0;
242                 }
243         }
244
245         parent = udev_device_get_parent_with_subsystem_devtype(pp->udev, "scsi", "scsi_target");
246         if (!parent)
247                 return 1;
248         /* Check for FibreChannel */
249         tgtdev = udev_device_get_parent(parent);
250         value = udev_device_get_sysname(tgtdev);
251         if (sscanf(value, "rport-%d:%d-%d",
252                    &host, &channel, &tgtid) == 3) {
253                 tgtdev = udev_device_new_from_subsystem_sysname(conf->udev,
254                                 "fc_remote_ports", value);
255                 if (tgtdev) {
256                         condlog(3, "SCSI target %d:%d:%d -> "
257                                 "FC rport %d:%d-%d",
258                                 pp->sg_id.host_no, pp->sg_id.channel,
259                                 pp->sg_id.scsi_id, host, channel,
260                                 tgtid);
261                         value = udev_device_get_sysattr_value(tgtdev,
262                                                               "node_name");
263                         if (value) {
264                                 pp->sg_id.proto_id = SCSI_PROTOCOL_FCP;
265                                 pp->sg_id.transport_id = tgtid;
266                                 strncpy(node, value, NODE_NAME_SIZE);
267                                 udev_device_unref(tgtdev);
268                                 return 0;
269                         } else
270                                 udev_device_unref(tgtdev);
271                 }
272         }
273
274         /* Check for iSCSI */
275         parent = pp->udev;
276         tgtname = NULL;
277         while (parent) {
278                 tgtname = udev_device_get_sysname(parent);
279                 if (tgtname && sscanf(tgtname , "session%d", &tgtid) == 1)
280                         break;
281                 parent = udev_device_get_parent(parent);
282                 tgtname = NULL;
283                 tgtid = -1;
284         }
285         if (parent && tgtname) {
286                 tgtdev = udev_device_new_from_subsystem_sysname(conf->udev,
287                                 "iscsi_session", tgtname);
288                 if (tgtdev) {
289                         const char *value;
290
291                         value = udev_device_get_sysattr_value(tgtdev, "targetname");
292                         if (value) {
293                                 pp->sg_id.proto_id = SCSI_PROTOCOL_ISCSI;
294                                 pp->sg_id.transport_id = tgtid;
295                                 strncpy(node, value, NODE_NAME_SIZE);
296                                 udev_device_unref(tgtdev);
297                                 return 0;
298                         }
299                         else
300                                 udev_device_unref(tgtdev);
301                 }
302         }
303         /* Check for libata */
304         parent = pp->udev;
305         tgtname = NULL;
306         while (parent) {
307                 tgtname = udev_device_get_sysname(parent);
308                 if (tgtname && sscanf(tgtname, "ata%d", &tgtid) == 1)
309                         break;
310                 parent = udev_device_get_parent(parent);
311                 tgtname = NULL;
312         }
313         if (tgtname) {
314                 pp->sg_id.proto_id = SCSI_PROTOCOL_ATA;
315                 pp->sg_id.transport_id = tgtid;
316                 snprintf(node, NODE_NAME_SIZE, "ata-%d.00", tgtid);
317                 return 0;
318         }
319         pp->sg_id.proto_id = SCSI_PROTOCOL_UNSPEC;
320         return 1;
321 }
322
323 int sysfs_get_host_adapter_name(struct path *pp, char *adapter_name)
324 {
325         int proto_id;
326
327         if (!pp || !adapter_name)
328                 return 1;
329
330         proto_id = pp->sg_id.proto_id;
331
332         if (proto_id != SCSI_PROTOCOL_FCP &&
333             proto_id != SCSI_PROTOCOL_SAS &&
334             proto_id != SCSI_PROTOCOL_ISCSI &&
335             proto_id != SCSI_PROTOCOL_SRP) {
336                 return 1;
337         }
338         /* iscsi doesn't have adapter info in sysfs
339          * get ip_address for grouping paths
340          */
341         if (pp->sg_id.proto_id == SCSI_PROTOCOL_ISCSI)
342                 return sysfs_get_iscsi_ip_address(pp, adapter_name);
343
344         /* fetch adapter pci name for other protocols
345          */
346         return sysfs_get_host_pci_name(pp, adapter_name);
347 }
348
349 int sysfs_get_host_pci_name(struct path *pp, char *pci_name)
350 {
351         struct udev_device *hostdev, *parent;
352         char host_name[HOST_NAME_LEN];
353         const char *driver_name, *value;
354
355         if (!pp || !pci_name)
356                 return 1;
357
358         sprintf(host_name, "host%d", pp->sg_id.host_no);
359         hostdev = udev_device_new_from_subsystem_sysname(conf->udev,
360                         "scsi_host", host_name);
361         if (!hostdev)
362                 return 1;
363
364         parent = udev_device_get_parent(hostdev);
365         while (parent) {
366                 driver_name = udev_device_get_driver(parent);
367                 if (!driver_name) {
368                         parent = udev_device_get_parent(parent);
369                         continue;
370                 }
371                 if (!strcmp(driver_name, "pcieport"))
372                         break;
373                 parent = udev_device_get_parent(parent);
374         }
375         if (parent) {
376                 /* pci_device found
377                  */
378                 value = udev_device_get_sysname(parent);
379
380                 strncpy(pci_name, value, SLOT_NAME_SIZE);
381                 udev_device_unref(hostdev);
382                 return 0;
383         }
384         udev_device_unref(hostdev);
385         return 1;
386 }
387
388 int sysfs_get_iscsi_ip_address(struct path *pp, char *ip_address)
389 {
390         struct udev_device *hostdev;
391         char host_name[HOST_NAME_LEN];
392         const char *value;
393
394         sprintf(host_name, "host%d", pp->sg_id.host_no);
395         hostdev = udev_device_new_from_subsystem_sysname(conf->udev,
396                         "iscsi_host", host_name);
397         if (hostdev) {
398                 value = udev_device_get_sysattr_value(hostdev,
399                                 "ipaddress");
400                 if (value) {
401                         strncpy(ip_address, value, SLOT_NAME_SIZE);
402                         udev_device_unref(hostdev);
403                         return 0;
404                 } else
405                         udev_device_unref(hostdev);
406         }
407         return 1;
408 }
409
410 static void
411 sysfs_set_rport_tmo(struct multipath *mpp, struct path *pp)
412 {
413         struct udev_device *rport_dev = NULL;
414         char value[16];
415         char rport_id[32];
416         unsigned long long tmo = 0;
417         int ret;
418
419         sprintf(rport_id, "rport-%d:%d-%d",
420                 pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id);
421         rport_dev = udev_device_new_from_subsystem_sysname(conf->udev,
422                                 "fc_remote_ports", rport_id);
423         if (!rport_dev) {
424                 condlog(1, "%s: No fc_remote_port device for '%s'", pp->dev,
425                         rport_id);
426                 return;
427         }
428         condlog(4, "target%d:%d:%d -> %s", pp->sg_id.host_no,
429                 pp->sg_id.channel, pp->sg_id.scsi_id, rport_id);
430
431         /*
432          * This is tricky.
433          * dev_loss_tmo will be limited to 600 if fast_io_fail
434          * is _not_ set.
435          * fast_io_fail will be limited by the current dev_loss_tmo
436          * setting.
437          * So to get everything right we first need to increase
438          * dev_loss_tmo to the fast_io_fail setting (if present),
439          * then set fast_io_fail, and _then_ set dev_loss_tmo
440          * to the correct value.
441          */
442         memset(value, 0, 16);
443         if (mpp->fast_io_fail != MP_FAST_IO_FAIL_UNSET &&
444             mpp->fast_io_fail != MP_FAST_IO_FAIL_ZERO &&
445             mpp->fast_io_fail != MP_FAST_IO_FAIL_OFF) {
446                 /* Check if we need to temporarily increase dev_loss_tmo */
447                 ret = sysfs_attr_get_value(rport_dev, "dev_loss_tmo",
448                                            value, 16);
449                 if (ret <= 0) {
450                         condlog(0, "%s: failed to read dev_loss_tmo value, "
451                                 "error %d", rport_id, -ret);
452                         goto out;
453                 }
454                 if (sscanf(value, "%llu\n", &tmo) != 1) {
455                         condlog(0, "%s: Cannot parse dev_loss_tmo "
456                                 "attribute '%s'", rport_id, value);
457                         goto out;
458                 }
459                 if (mpp->fast_io_fail >= tmo) {
460                         snprintf(value, 16, "%u", mpp->fast_io_fail + 1);
461                 }
462         } else if (mpp->dev_loss > 600) {
463                 condlog(3, "%s: limiting dev_loss_tmo to 600, since "
464                         "fast_io_fail is not set", rport_id);
465                 snprintf(value, 16, "%u", 600);
466         } else {
467                 snprintf(value, 16, "%u", mpp->dev_loss);
468         }
469         if (strlen(value)) {
470                 ret = sysfs_attr_set_value(rport_dev, "dev_loss_tmo",
471                                            value, strlen(value));
472                 if (ret <= 0) {
473                         if (ret == -EBUSY)
474                                 condlog(3, "%s: rport blocked", rport_id);
475                         else
476                                 condlog(0, "%s: failed to set dev_loss_tmo to %s, error %d",
477                                         rport_id, value, -ret);
478                         goto out;
479                 }
480         }
481         if (mpp->fast_io_fail != MP_FAST_IO_FAIL_UNSET) {
482                 if (mpp->fast_io_fail == MP_FAST_IO_FAIL_OFF)
483                         sprintf(value, "off");
484                 else if (mpp->fast_io_fail == MP_FAST_IO_FAIL_ZERO)
485                         sprintf(value, "0");
486                 else
487                         snprintf(value, 16, "%u", mpp->fast_io_fail);
488                 ret = sysfs_attr_set_value(rport_dev, "fast_io_fail_tmo",
489                                            value, strlen(value));
490                 if (ret <= 0) {
491                         if (ret == -EBUSY)
492                                 condlog(3, "%s: rport blocked", rport_id);
493                         else
494                                 condlog(0, "%s: failed to set fast_io_fail_tmo to %s, error %d",
495                                         rport_id, value, -ret);
496                 }
497         }
498         if (tmo > 0) {
499                 snprintf(value, 16, "%u", mpp->dev_loss);
500                 ret = sysfs_attr_set_value(rport_dev, "dev_loss_tmo",
501                                            value, strlen(value));
502                 if (ret <= 0) {
503                         if (ret == -EBUSY)
504                                 condlog(3, "%s: rport blocked", rport_id);
505                         else
506                                 condlog(0, "%s: failed to set dev_loss_tmo to %s, error %d",
507                                         rport_id, value, -ret);
508                 }
509         }
510 out:
511         udev_device_unref(rport_dev);
512 }
513
514 static void
515 sysfs_set_session_tmo(struct multipath *mpp, struct path *pp)
516 {
517         struct udev_device *session_dev = NULL;
518         char session_id[64];
519         char value[11];
520
521         sprintf(session_id, "session%d", pp->sg_id.transport_id);
522         session_dev = udev_device_new_from_subsystem_sysname(conf->udev,
523                                 "iscsi_session", session_id);
524         if (!session_dev) {
525                 condlog(1, "%s: No iscsi session for '%s'", pp->dev,
526                         session_id);
527                 return;
528         }
529         condlog(4, "target%d:%d:%d -> %s", pp->sg_id.host_no,
530                 pp->sg_id.channel, pp->sg_id.scsi_id, session_id);
531
532         if (mpp->dev_loss) {
533                 condlog(3, "%s: ignoring dev_loss_tmo on iSCSI", pp->dev);
534         }
535         if (mpp->fast_io_fail != MP_FAST_IO_FAIL_UNSET) {
536                 if (mpp->fast_io_fail == MP_FAST_IO_FAIL_OFF) {
537                         condlog(3, "%s: can't switch off fast_io_fail_tmo "
538                                 "on iSCSI", pp->dev);
539                 } else if (mpp->fast_io_fail == MP_FAST_IO_FAIL_ZERO) {
540                         condlog(3, "%s: can't set fast_io_fail_tmo to '0'"
541                                 "on iSCSI", pp->dev);
542                 } else {
543                         snprintf(value, 11, "%u", mpp->fast_io_fail);
544                         if (sysfs_attr_set_value(session_dev, "recovery_tmo",
545                                                  value, 11) <= 0) {
546                                 condlog(3, "%s: Failed to set recovery_tmo, "
547                                         " error %d", pp->dev, errno);
548                         }
549                 }
550         }
551         udev_device_unref(session_dev);
552         return;
553 }
554
555 static void
556 sysfs_set_nexus_loss_tmo(struct multipath *mpp, struct path *pp)
557 {
558         struct udev_device *sas_dev = NULL;
559         char end_dev_id[64];
560         char value[11];
561
562         sprintf(end_dev_id, "end_device-%d:%d",
563                 pp->sg_id.host_no, pp->sg_id.transport_id);
564         sas_dev = udev_device_new_from_subsystem_sysname(conf->udev,
565                                 "sas_end_device", end_dev_id);
566         if (!sas_dev) {
567                 condlog(1, "%s: No SAS end device for '%s'", pp->dev,
568                         end_dev_id);
569                 return;
570         }
571         condlog(4, "target%d:%d:%d -> %s", pp->sg_id.host_no,
572                 pp->sg_id.channel, pp->sg_id.scsi_id, end_dev_id);
573
574         if (mpp->dev_loss) {
575                 snprintf(value, 11, "%u", mpp->dev_loss);
576                 if (sysfs_attr_set_value(sas_dev, "I_T_nexus_loss_timeout",
577                                          value, 11) <= 0)
578                         condlog(3, "%s: failed to update "
579                                 "I_T Nexus loss timeout, error %d",
580                                 pp->dev, errno);
581         }
582         udev_device_unref(sas_dev);
583         return;
584 }
585
586 int
587 sysfs_set_scsi_tmo (struct multipath *mpp)
588 {
589         struct path *pp;
590         int i;
591         int dev_loss_tmo = mpp->dev_loss;
592
593         if (mpp->no_path_retry > 0) {
594                 int no_path_retry_tmo = mpp->no_path_retry * conf->checkint;
595
596                 if (no_path_retry_tmo > MAX_DEV_LOSS_TMO)
597                         no_path_retry_tmo = MAX_DEV_LOSS_TMO;
598                 if (no_path_retry_tmo > dev_loss_tmo)
599                         dev_loss_tmo = no_path_retry_tmo;
600                 condlog(3, "%s: update dev_loss_tmo to %d",
601                         mpp->alias, dev_loss_tmo);
602         } else if (mpp->no_path_retry == NO_PATH_RETRY_QUEUE) {
603                 dev_loss_tmo = MAX_DEV_LOSS_TMO;
604                 condlog(3, "%s: update dev_loss_tmo to %d",
605                         mpp->alias, dev_loss_tmo);
606         }
607         mpp->dev_loss = dev_loss_tmo;
608         if (mpp->dev_loss && mpp->fast_io_fail >= (int)mpp->dev_loss) {
609                 condlog(3, "%s: turning off fast_io_fail (%d is not smaller than dev_loss_tmo)",
610                         mpp->alias, mpp->fast_io_fail);
611                 mpp->fast_io_fail = MP_FAST_IO_FAIL_OFF;
612         }
613         if (!mpp->dev_loss && mpp->fast_io_fail == MP_FAST_IO_FAIL_UNSET)
614                 return 0;
615
616         vector_foreach_slot(mpp->paths, pp, i) {
617                 if (pp->sg_id.proto_id == SCSI_PROTOCOL_FCP)
618                         sysfs_set_rport_tmo(mpp, pp);
619                 if (pp->sg_id.proto_id == SCSI_PROTOCOL_ISCSI)
620                         sysfs_set_session_tmo(mpp, pp);
621                 if (pp->sg_id.proto_id == SCSI_PROTOCOL_SAS)
622                         sysfs_set_nexus_loss_tmo(mpp, pp);
623         }
624         return 0;
625 }
626
627 int
628 do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
629        void *resp, int mx_resp_len)
630 {
631         unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
632                 { INQUIRY_CMD, 0, 0, 0, 0, 0 };
633         unsigned char sense_b[SENSE_BUFF_LEN];
634         struct sg_io_hdr io_hdr;
635
636         if (cmddt)
637                 inqCmdBlk[1] |= 2;
638         if (evpd)
639                 inqCmdBlk[1] |= 1;
640         inqCmdBlk[2] = (unsigned char) pg_op;
641         inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff);
642         inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff);
643         memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
644         memset(sense_b, 0, SENSE_BUFF_LEN);
645         io_hdr.interface_id = 'S';
646         io_hdr.cmd_len = sizeof (inqCmdBlk);
647         io_hdr.mx_sb_len = sizeof (sense_b);
648         io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
649         io_hdr.dxfer_len = mx_resp_len;
650         io_hdr.dxferp = resp;
651         io_hdr.cmdp = inqCmdBlk;
652         io_hdr.sbp = sense_b;
653         io_hdr.timeout = DEF_TIMEOUT;
654
655         if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
656                 return -1;
657
658         /* treat SG_ERR here to get rid of sg_err.[ch] */
659         io_hdr.status &= 0x7e;
660         if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
661             (0 == io_hdr.driver_status))
662                 return 0;
663         if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
664             (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
665             (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
666                 if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
667                         int sense_key;
668                         unsigned char * sense_buffer = io_hdr.sbp;
669                         if (sense_buffer[0] & 0x2)
670                                 sense_key = sense_buffer[1] & 0xf;
671                         else
672                                 sense_key = sense_buffer[2] & 0xf;
673                         if(RECOVERED_ERROR == sense_key)
674                                 return 0;
675                 }
676         }
677         return -1;
678 }
679
680 static int
681 get_serial (char * str, int maxlen, int fd)
682 {
683         int len = 0;
684         char buff[MX_ALLOC_LEN + 1] = {0};
685
686         if (fd < 0)
687                 return 1;
688
689         if (0 == do_inq(fd, 0, 1, 0x80, buff, MX_ALLOC_LEN)) {
690                 len = buff[3];
691                 if (len >= maxlen)
692                         return 1;
693                 if (len > 0) {
694                         memcpy(str, buff + 4, len);
695                         str[len] = '\0';
696                 }
697                 return 0;
698         }
699         return 1;
700 }
701
702 static int
703 get_geometry(struct path *pp)
704 {
705         if (pp->fd < 0)
706                 return 1;
707
708         if (ioctl(pp->fd, HDIO_GETGEO, &pp->geom)) {
709                 condlog(2, "%s: HDIO_GETGEO failed with %d", pp->dev, errno);
710                 memset(&pp->geom, 0, sizeof(pp->geom));
711                 return 1;
712         }
713         condlog(3, "%s: %u cyl, %u heads, %u sectors/track, start at %lu",
714                 pp->dev, pp->geom.cylinders, pp->geom.heads,
715                 pp->geom.sectors, pp->geom.start);
716         return 0;
717 }
718
719 static int
720 scsi_sysfs_pathinfo (struct path * pp)
721 {
722         struct udev_device *parent;
723         const char *attr_path = NULL;
724
725         parent = pp->udev;
726         while (parent) {
727                 const char *subsys = udev_device_get_subsystem(parent);
728                 if (subsys && !strncmp(subsys, "scsi", 4)) {
729                         attr_path = udev_device_get_sysname(parent);
730                         if (!attr_path)
731                                 break;
732                         if (sscanf(attr_path, "%i:%i:%i:%i",
733                                    &pp->sg_id.host_no,
734                                    &pp->sg_id.channel,
735                                    &pp->sg_id.scsi_id,
736                                    &pp->sg_id.lun) == 4)
737                                 break;
738                 }
739                 parent = udev_device_get_parent(parent);
740         }
741         if (!attr_path || pp->sg_id.host_no == -1)
742                 return 1;
743
744         if (sysfs_get_vendor(parent, pp->vendor_id, SCSI_VENDOR_SIZE) <= 0)
745                 return 1;
746
747         condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
748
749         if (sysfs_get_model(parent, pp->product_id, SCSI_PRODUCT_SIZE) <= 0)
750                 return 1;
751
752         condlog(3, "%s: product = %s", pp->dev, pp->product_id);
753
754         if (sysfs_get_rev(parent, pp->rev, SCSI_REV_SIZE) <= 0)
755                 return 1;
756
757         condlog(3, "%s: rev = %s", pp->dev, pp->rev);
758
759         /*
760          * set the hwe configlet pointer
761          */
762         pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, pp->rev);
763
764         /*
765          * host / bus / target / lun
766          */
767         condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
768                         pp->dev,
769                         pp->sg_id.host_no,
770                         pp->sg_id.channel,
771                         pp->sg_id.scsi_id,
772                         pp->sg_id.lun);
773
774         /*
775          * target node name
776          */
777         if(!sysfs_get_tgt_nodename(pp, pp->tgt_node_name)) {
778                 condlog(3, "%s: tgt_node_name = %s",
779                         pp->dev, pp->tgt_node_name);
780         }
781
782         return 0;
783 }
784
785 static int
786 ccw_sysfs_pathinfo (struct path * pp)
787 {
788         struct udev_device *parent;
789         char attr_buff[NAME_SIZE];
790         const char *attr_path;
791
792         parent = pp->udev;
793         while (parent) {
794                 const char *subsys = udev_device_get_subsystem(parent);
795                 if (subsys && !strncmp(subsys, "ccw", 3))
796                         break;
797                 parent = udev_device_get_parent(parent);
798         }
799         if (!parent)
800                 return 1;
801
802         sprintf(pp->vendor_id, "IBM");
803
804         condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
805
806         if (sysfs_get_devtype(parent, attr_buff, FILE_NAME_SIZE) <= 0)
807                 return 1;
808
809         if (!strncmp(attr_buff, "3370", 4)) {
810                 sprintf(pp->product_id,"S/390 DASD FBA");
811         } else if (!strncmp(attr_buff, "9336", 4)) {
812                 sprintf(pp->product_id,"S/390 DASD FBA");
813         } else {
814                 sprintf(pp->product_id,"S/390 DASD ECKD");
815         }
816
817         condlog(3, "%s: product = %s", pp->dev, pp->product_id);
818
819         /*
820          * set the hwe configlet pointer
821          */
822         pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, NULL);
823
824         /*
825          * host / bus / target / lun
826          */
827         attr_path = udev_device_get_sysname(parent);
828         pp->sg_id.lun = 0;
829         sscanf(attr_path, "%i.%i.%x",
830                         &pp->sg_id.host_no,
831                         &pp->sg_id.channel,
832                         &pp->sg_id.scsi_id);
833         condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
834                         pp->dev,
835                         pp->sg_id.host_no,
836                         pp->sg_id.channel,
837                         pp->sg_id.scsi_id,
838                         pp->sg_id.lun);
839
840         return 0;
841 }
842
843 static int
844 cciss_sysfs_pathinfo (struct path * pp)
845 {
846         const char * attr_path = NULL;
847         struct udev_device *parent;
848
849         parent = pp->udev;
850         while (parent) {
851                 const char *subsys = udev_device_get_subsystem(parent);
852                 if (subsys && !strncmp(subsys, "cciss", 5)) {
853                         attr_path = udev_device_get_sysname(parent);
854                         if (!attr_path)
855                                 break;
856                         if (sscanf(attr_path, "c%id%i",
857                                    &pp->sg_id.host_no,
858                                    &pp->sg_id.scsi_id) == 2)
859                                 break;
860                 }
861                 parent = udev_device_get_parent(parent);
862         }
863         if (!attr_path || pp->sg_id.host_no == -1)
864                 return 1;
865
866         if (sysfs_get_vendor(parent, pp->vendor_id, SCSI_VENDOR_SIZE) <= 0)
867                 return 1;
868
869         condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
870
871         if (sysfs_get_model(parent, pp->product_id, SCSI_PRODUCT_SIZE) <= 0)
872                 return 1;
873
874         condlog(3, "%s: product = %s", pp->dev, pp->product_id);
875
876         if (sysfs_get_rev(parent, pp->rev, SCSI_REV_SIZE) <= 0)
877                 return 1;
878
879         condlog(3, "%s: rev = %s", pp->dev, pp->rev);
880
881         /*
882          * set the hwe configlet pointer
883          */
884         pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, pp->rev);
885
886         /*
887          * host / bus / target / lun
888          */
889         pp->sg_id.lun = 0;
890         pp->sg_id.channel = 0;
891         condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
892                 pp->dev,
893                 pp->sg_id.host_no,
894                 pp->sg_id.channel,
895                 pp->sg_id.scsi_id,
896                 pp->sg_id.lun);
897         return 0;
898 }
899
900 static int
901 common_sysfs_pathinfo (struct path * pp)
902 {
903         if (!pp)
904                 return 1;
905
906         if (!pp->udev) {
907                 condlog(4, "%s: udev not initialised", pp->dev);
908                 return 1;
909         }
910         if (sysfs_get_dev(pp->udev, pp->dev_t, BLK_DEV_SIZE) <= 0) {
911                 condlog(3, "%s: no 'dev' attribute in sysfs", pp->dev);
912                 return 1;
913         }
914
915         condlog(3, "%s: dev_t = %s", pp->dev, pp->dev_t);
916
917         if (sysfs_get_size(pp, &pp->size))
918                 return 1;
919
920         condlog(3, "%s: size = %llu", pp->dev, pp->size);
921
922         return 0;
923 }
924
925 int
926 path_offline (struct path * pp)
927 {
928         struct udev_device * parent;
929         char buff[SCSI_STATE_SIZE];
930         int err;
931
932         if (pp->bus != SYSFS_BUS_SCSI)
933                 return PATH_UP;
934
935         parent = pp->udev;
936         while (parent) {
937                 const char *subsys = udev_device_get_subsystem(parent);
938                 if (subsys && !strncmp(subsys, "scsi", 4))
939                         break;
940                 parent = udev_device_get_parent(parent);
941         }
942
943         if (!parent) {
944                 condlog(1, "%s: failed to get sysfs information", pp->dev);
945                 return PATH_REMOVED;
946         }
947
948         memset(buff, 0x0, SCSI_STATE_SIZE);
949         err = sysfs_attr_get_value(parent, "state", buff, SCSI_STATE_SIZE);
950         if (err <= 0) {
951                 if (err == -ENXIO)
952                         return PATH_REMOVED;
953                 else
954                         return PATH_DOWN;
955         }
956
957
958         condlog(3, "%s: path state = %s", pp->dev, buff);
959
960         if (!strncmp(buff, "offline", 7)) {
961                 pp->offline = 1;
962                 return PATH_DOWN;
963         }
964         pp->offline = 0;
965         if (!strncmp(buff, "blocked", 7) || !strncmp(buff, "quiesce", 7))
966                 return PATH_PENDING;
967         else if (!strncmp(buff, "running", 7))
968                 return PATH_UP;
969
970         return PATH_DOWN;
971 }
972
973 int
974 sysfs_pathinfo(struct path * pp)
975 {
976         if (common_sysfs_pathinfo(pp))
977                 return 1;
978
979         pp->bus = SYSFS_BUS_UNDEF;
980         if (!strncmp(pp->dev,"cciss",5))
981                 pp->bus = SYSFS_BUS_CCISS;
982         if (!strncmp(pp->dev,"dasd", 4))
983                 pp->bus = SYSFS_BUS_CCW;
984         if (!strncmp(pp->dev,"sd", 2))
985                 pp->bus = SYSFS_BUS_SCSI;
986
987         if (pp->bus == SYSFS_BUS_UNDEF)
988                 return 0;
989         else if (pp->bus == SYSFS_BUS_SCSI) {
990                 if (scsi_sysfs_pathinfo(pp))
991                         return 1;
992         } else if (pp->bus == SYSFS_BUS_CCW) {
993                 if (ccw_sysfs_pathinfo(pp))
994                         return 1;
995         } else if (pp->bus == SYSFS_BUS_CCISS) {
996                 if (cciss_sysfs_pathinfo(pp))
997                         return 1;
998         }
999         return 0;
1000 }
1001
1002 static int
1003 scsi_ioctl_pathinfo (struct path * pp, int mask)
1004 {
1005         if (mask & DI_SERIAL) {
1006                 get_serial(pp->serial, SERIAL_SIZE, pp->fd);
1007                 condlog(3, "%s: serial = %s", pp->dev, pp->serial);
1008         }
1009
1010         return 0;
1011 }
1012
1013 static int
1014 cciss_ioctl_pathinfo (struct path * pp, int mask)
1015 {
1016         if (mask & DI_SERIAL) {
1017                 get_serial(pp->serial, SERIAL_SIZE, pp->fd);
1018                 condlog(3, "%s: serial = %s", pp->dev, pp->serial);
1019         }
1020         return 0;
1021 }
1022
1023 int
1024 get_state (struct path * pp, int daemon)
1025 {
1026         struct checker * c = &pp->checker;
1027         int state;
1028
1029         condlog(3, "%s: get_state", pp->dev);
1030
1031         if (!checker_selected(c)) {
1032                 if (daemon) {
1033                         if (pathinfo(pp, conf->hwtable, DI_SYSFS) != PATHINFO_OK) {
1034                                 condlog(3, "%s: couldn't get sysfs pathinfo",
1035                                         pp->dev);
1036                                 return PATH_UNCHECKED;
1037                         }
1038                 }
1039                 select_checker(pp);
1040                 if (!checker_selected(c)) {
1041                         condlog(3, "%s: No checker selected", pp->dev);
1042                         return PATH_UNCHECKED;
1043                 }
1044                 checker_set_fd(c, pp->fd);
1045                 if (checker_init(c, pp->mpp?&pp->mpp->mpcontext:NULL)) {
1046                         memset(c, 0x0, sizeof(struct checker));
1047                         condlog(3, "%s: checker init failed", pp->dev);
1048                         return PATH_UNCHECKED;
1049                 }
1050         }
1051         checker_clear_message(c);
1052         if (daemon) {
1053                 if (conf->force_sync == 0)
1054                         checker_set_async(c);
1055                 else
1056                         checker_set_sync(c);
1057         }
1058         if (!conf->checker_timeout &&
1059             sysfs_get_timeout(pp, &(c->timeout)) <= 0)
1060                 c->timeout = DEF_TIMEOUT;
1061         state = checker_check(c);
1062         condlog(3, "%s: state = %s", pp->dev, checker_state_name(state));
1063         if (state != PATH_UP && state != PATH_GHOST &&
1064             strlen(checker_message(c)))
1065                 condlog(3, "%s: checker msg is \"%s\"",
1066                         pp->dev, checker_message(c));
1067         return state;
1068 }
1069
1070 static int
1071 get_prio (struct path * pp)
1072 {
1073         if (!pp)
1074                 return 0;
1075
1076         struct prio * p = &pp->prio;
1077
1078         if (!prio_selected(p)) {
1079                 select_detect_prio(pp);
1080                 select_prio(pp);
1081                 if (!prio_selected(p)) {
1082                         condlog(3, "%s: no prio selected", pp->dev);
1083                         pp->priority = PRIO_UNDEF;
1084                         return 1;
1085                 }
1086         }
1087         pp->priority = prio_getprio(p, pp);
1088         if (pp->priority < 0) {
1089                 condlog(3, "%s: %s prio error", pp->dev, prio_name(p));
1090                 pp->priority = PRIO_UNDEF;
1091                 return 1;
1092         }
1093         condlog(3, "%s: %s prio = %u",
1094                 pp->dev, prio_name(p), pp->priority);
1095         return 0;
1096 }
1097
1098 static int
1099 get_uid (struct path * pp)
1100 {
1101         char *c;
1102         const char *origin;
1103
1104         if (!pp->uid_attribute && !pp->getuid)
1105                 select_getuid(pp);
1106
1107         if (!pp->udev) {
1108                 condlog(1, "%s: no udev information", pp->dev);
1109                 return 1;
1110         }
1111
1112         memset(pp->wwid, 0, WWID_SIZE);
1113         if (pp->getuid) {
1114                 char buff[CALLOUT_MAX_SIZE];
1115
1116                 /* Use 'getuid' callout, deprecated */
1117                 condlog(1, "%s: using deprecated getuid callout", pp->dev);
1118                 if (apply_format(pp->getuid, &buff[0], pp)) {
1119                         condlog(0, "error formatting uid callout command");
1120                         memset(pp->wwid, 0, WWID_SIZE);
1121                 } else if (execute_program(buff, pp->wwid, WWID_SIZE)) {
1122                         condlog(3, "error calling out %s", buff);
1123                         memset(pp->wwid, 0, WWID_SIZE);
1124                 }
1125                 origin = "callout";
1126         } else {
1127                 const char *value;
1128
1129                 value = udev_device_get_property_value(pp->udev,
1130                                                        pp->uid_attribute);
1131                 if ((!value || strlen(value) == 0) &&
1132                     conf->cmd == CMD_VALID_PATH)
1133                         value = getenv(pp->uid_attribute);
1134                 if (value && strlen(value)) {
1135                         size_t len = WWID_SIZE;
1136
1137                         if (strlen(value) + 1 > WWID_SIZE) {
1138                                 condlog(0, "%s: wwid overflow", pp->dev);
1139                         } else {
1140                                 len = strlen(value);
1141                         }
1142                         strncpy(pp->wwid, value, len);
1143                 } else {
1144                         condlog(3, "%s: no %s attribute", pp->dev,
1145                                 pp->uid_attribute);
1146                 }
1147                 origin = "udev";
1148         }
1149         /* Strip any trailing blanks */
1150         c = strchr(pp->wwid, '\0');
1151         c--;
1152         while (c && c >= pp->wwid && *c == ' ') {
1153                 *c = '\0';
1154                 c--;
1155         }
1156         condlog(3, "%s: uid = %s (%s)", pp->dev,
1157                 *pp->wwid == '\0' ? "<empty>" : pp->wwid, origin);
1158         return 0;
1159 }
1160
1161 extern int
1162 pathinfo (struct path *pp, vector hwtable, int mask)
1163 {
1164         int path_state;
1165
1166         if (!pp)
1167                 return PATHINFO_FAILED;
1168
1169         condlog(3, "%s: mask = 0x%x", pp->dev, mask);
1170
1171         /*
1172          * fetch info available in sysfs
1173          */
1174         if (mask & DI_SYSFS && sysfs_pathinfo(pp))
1175                 return PATHINFO_FAILED;
1176
1177         if (mask & DI_BLACKLIST && mask & DI_SYSFS) {
1178                 if (filter_device(conf->blist_device, conf->elist_device,
1179                                   pp->vendor_id, pp->product_id) > 0) {
1180                         return PATHINFO_SKIPPED;
1181                 }
1182         }
1183
1184         path_state = path_offline(pp);
1185         if (path_state == PATH_REMOVED)
1186                 goto blank;
1187
1188         /*
1189          * fetch info not available through sysfs
1190          */
1191         if (pp->fd < 0)
1192                 pp->fd = open(udev_device_get_devnode(pp->udev), O_RDONLY);
1193
1194         if (pp->fd < 0) {
1195                 condlog(4, "Couldn't open node for %s: %s",
1196                         pp->dev, strerror(errno));
1197                 goto blank;
1198         }
1199
1200         if (mask & DI_SERIAL)
1201                 get_geometry(pp);
1202
1203         if (path_state == PATH_UP && pp->bus == SYSFS_BUS_SCSI &&
1204             scsi_ioctl_pathinfo(pp, mask))
1205                 goto blank;
1206
1207         if (pp->bus == SYSFS_BUS_CCISS &&
1208             cciss_ioctl_pathinfo(pp, mask))
1209                 goto blank;
1210
1211         if (mask & DI_CHECKER) {
1212                 if (path_state == PATH_UP) {
1213                         pp->chkrstate = pp->state = get_state(pp, 0);
1214                         if (pp->state == PATH_UNCHECKED ||
1215                             pp->state == PATH_WILD)
1216                                 goto blank;
1217                         if (pp->state == PATH_TIMEOUT)
1218                                 pp->state = PATH_DOWN;
1219                 } else {
1220                         condlog(3, "%s: path inaccessible", pp->dev);
1221                         pp->chkrstate = pp->state = path_state;
1222                         if (path_state == PATH_PENDING ||
1223                             path_state == PATH_DOWN)
1224                                 pp->priority = 0;
1225                 }
1226         }
1227
1228         if ((mask & DI_WWID) && !strlen(pp->wwid))
1229                 get_uid(pp);
1230         if (mask & DI_BLACKLIST && mask & DI_WWID) {
1231                 if (!strlen(pp->wwid) ||
1232                     filter_wwid(conf->blist_wwid, conf->elist_wwid,
1233                                 pp->wwid, pp->dev) > 0) {
1234                         return PATHINFO_SKIPPED;
1235                 }
1236         }
1237
1238          /*
1239           * Retrieve path priority, even for PATH_DOWN paths if it has never
1240           * been successfully obtained before.
1241           */
1242         if ((mask & DI_PRIO) && path_state == PATH_UP) {
1243                 if (pp->state != PATH_DOWN || pp->priority == PRIO_UNDEF) {
1244                         if (!strlen(pp->wwid))
1245                                 get_uid(pp);
1246                         if (!strlen(pp->wwid))
1247                                 return PATHINFO_SKIPPED;
1248                         get_prio(pp);
1249                 }
1250         }
1251
1252         pp->initialized = 1;
1253         return PATHINFO_OK;
1254
1255 blank:
1256         /*
1257          * Recoverable error, for example faulty or offline path
1258          */
1259         memset(pp->wwid, 0, WWID_SIZE);
1260         pp->chkrstate = pp->state = PATH_DOWN;
1261         pp->initialized = 0;
1262
1263         return 0;
1264 }