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