2 * Copyright (c) 2004, 2005, 2006 Christophe Varoqui
3 * Copyright (c) 2005 Stefan Bader, IBM
4 * Copyright (c) 2005 Mike Anderson
21 #include "blacklist.h"
25 #include "sg_include.h"
27 #include "discovery.h"
32 store_pathinfo (vector pathvec, vector hwtable, char * devname, int flag)
41 if(safe_sprintf(pp->dev, "%s", devname)) {
42 condlog(0, "pp->dev too small");
45 if (pathinfo(pp, hwtable, flag))
48 if (store_path(pathvec, pp))
58 path_discover (vector pathvec, struct config * conf, char * devname, int flag)
60 char path[FILE_NAME_SIZE];
66 if (filter_devnode(conf->blist_devnode, conf->elist_devnode,
70 if(safe_sprintf(path, "%s/block/%s/device", sysfs_path,
72 condlog(0, "path too small");
76 if (strncmp(devname,"cciss",5) && !filepresent(path)) {
77 condlog(4, "path %s not present", path);
81 pp = find_path_by_dev(pathvec, devname);
84 pp = store_pathinfo(pathvec, conf->hwtable,
88 return pathinfo(pp, conf->hwtable, flag);
92 path_discovery (vector pathvec, struct config * conf, int flag)
95 struct dirent *blkdev;
97 char devpath[PATH_MAX];
101 if (!(blkdir = opendir("/sys/block")))
104 strcpy(devpath,"/sys/block");
105 while ((blkdev = readdir(blkdir)) != NULL) {
106 if ((strcmp(blkdev->d_name,".") == 0) ||
107 (strcmp(blkdev->d_name,"..") == 0))
110 devptr = devpath + 10;
113 strcat(devptr,blkdev->d_name);
114 if (stat(devpath, &statbuf) < 0)
117 if (S_ISDIR(statbuf.st_mode) == 0)
120 condlog(4, "Discover device %s", devpath);
122 r += path_discover(pathvec, conf, blkdev->d_name, flag);
125 condlog(4, "Discovery status %d", r);
129 #define declare_sysfs_get_str(fname) \
131 sysfs_get_##fname (struct sysfs_device * dev, char * buff, size_t len) \
135 size = sysfs_attr_get_value(dev->devpath, #fname, buff, len); \
137 condlog(3, "%s: attribute %s not found in sysfs", \
138 dev->kernel, #fname); \
142 condlog(3, "%s: overflow in attribute %s", \
143 dev->kernel, #fname); \
150 declare_sysfs_get_str(devtype);
151 declare_sysfs_get_str(cutype);
152 declare_sysfs_get_str(vendor);
153 declare_sysfs_get_str(model);
154 declare_sysfs_get_str(rev);
155 declare_sysfs_get_str(state);
156 declare_sysfs_get_str(dev);
159 sysfs_get_timeout(struct sysfs_device *dev, unsigned int *timeout)
161 char attr_path[SYSFS_PATH_SIZE], attr[NAME_SIZE];
166 if (safe_sprintf(attr_path, "%s/device", dev->devpath))
169 len = sysfs_attr_get_value(attr_path, "timeout", attr, NAME_SIZE);
171 condlog(3, "%s: No timeout value in sysfs", dev->devpath);
175 r = sscanf(attr, "%u\n", &t);
178 condlog(3, "%s: Cannot parse timeout attribute '%s'",
189 sysfs_get_size (struct sysfs_device * dev, unsigned long long * size)
191 char attr[NAME_SIZE];
195 len = sysfs_attr_get_value(dev->devpath, "size", attr, NAME_SIZE);
197 condlog(3, "%s: No size attribute in sysfs", dev->devpath);
201 r = sscanf(attr, "%llu\n", size);
204 condlog(3, "%s: Cannot parse size attribute '%s'",
213 sysfs_get_tgt_nodename (struct sysfs_device * dev, char * node,
214 unsigned int host, unsigned int channel,
217 unsigned int checkhost, session;
218 char attr_path[SYSFS_PATH_SIZE];
221 if (safe_sprintf(attr_path,
222 "/class/fc_transport/target%i:%i:%i",
223 host, channel, target)) {
224 condlog(0, "attr_path too small");
228 len = sysfs_attr_get_value(attr_path, "node_name", node, NODE_NAME_SIZE);
232 if (sscanf(dev->devpath, "/devices/platform/host%u/session%u/",
233 &checkhost, &session) != 2)
235 if (checkhost != host)
237 if (safe_sprintf(attr_path, "/devices/platform/host%u/session%u/iscsi_session/session%u", host, session, session)) {
238 condlog(0, "attr_path too small");
242 len = sysfs_attr_get_value(attr_path, "targetname", node,
251 find_rport_id(struct path *pp)
253 char attr_path[SYSFS_PATH_SIZE];
255 int host, channel, rport_id = -1;
257 if (safe_sprintf(attr_path,
258 "/class/fc_transport/target%i:%i:%i",
259 pp->sg_id.host_no, pp->sg_id.channel,
260 pp->sg_id.scsi_id)) {
261 condlog(0, "attr_path too small for target");
265 if (sysfs_resolve_link(attr_path, SYSFS_PATH_SIZE))
268 condlog(4, "target%d:%d:%d -> path %s", pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.scsi_id, attr_path);
271 base = basename(dir);
274 if (sscanf((const char *)base, "rport-%d:%d-%d", &host, &channel, &rport_id) == 3)
276 } while (strcmp((const char *)dir, "/"));
281 condlog(4, "target%d:%d:%d -> rport_id %d", pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.scsi_id, rport_id);
286 sysfs_set_scsi_tmo (struct multipath *mpp)
288 char attr_path[SYSFS_PATH_SIZE];
293 int dev_loss_tmo = mpp->dev_loss;
295 if (mpp->no_path_retry > 0) {
296 int no_path_retry_tmo = mpp->no_path_retry * conf->checkint;
298 if (no_path_retry_tmo > MAX_DEV_LOSS_TMO)
299 no_path_retry_tmo = MAX_DEV_LOSS_TMO;
300 if (no_path_retry_tmo > dev_loss_tmo)
301 dev_loss_tmo = no_path_retry_tmo;
302 condlog(3, "%s: update dev_loss_tmo to %d",
303 mpp->alias, dev_loss_tmo);
304 } else if (mpp->no_path_retry == NO_PATH_RETRY_QUEUE) {
305 dev_loss_tmo = MAX_DEV_LOSS_TMO;
306 condlog(3, "%s: update dev_loss_tmo to %d",
307 mpp->alias, dev_loss_tmo);
309 mpp->dev_loss = dev_loss_tmo;
310 if (mpp->fast_io_fail > (int)mpp->dev_loss) {
311 mpp->fast_io_fail = mpp->dev_loss;
312 condlog(3, "%s: update fast_io_fail to %d",
313 mpp->alias, mpp->fast_io_fail);
315 if (!mpp->dev_loss && !mpp->fast_io_fail)
318 vector_foreach_slot(mpp->paths, pp, i) {
319 rport_id = find_rport_id(pp);
321 condlog(3, "failed to find rport_id for target%d:%d:%d", pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.scsi_id);
325 if (safe_snprintf(attr_path, SYSFS_PATH_SIZE,
326 "/class/fc_remote_ports/rport-%d:%d-%d",
327 pp->sg_id.host_no, pp->sg_id.channel,
329 condlog(0, "attr_path '/class/fc_remote_ports/rport-%d:%d-%d' too large", pp->sg_id.host_no, pp->sg_id.channel, rport_id);
333 snprintf(value, 11, "%u", mpp->dev_loss);
334 if (sysfs_attr_set_value(attr_path, "dev_loss_tmo",
337 if (mpp->fast_io_fail <= 0 && mpp->dev_loss > 600) {
338 strncpy(value, "600", 4);
339 condlog(3, "%s: limiting dev_loss_tmo to 600, since fast_io_fail is not set", mpp->alias);
340 if (sysfs_attr_set_value(attr_path, "dev_loss_tmo", value, 11) >= 0)
344 condlog(0, "%s failed to set %s/dev_loss_tmo", mpp->alias, attr_path);
349 if (mpp->fast_io_fail){
350 if (mpp->fast_io_fail == -1)
351 sprintf(value, "off");
353 snprintf(value, 11, "%u", mpp->fast_io_fail);
354 if (sysfs_attr_set_value(attr_path, "fast_io_fail_tmo",
357 "%s failed to set %s/fast_io_fail_tmo",
358 mpp->alias, attr_path);
367 opennode (char * dev, int mode)
369 char devpath[FILE_NAME_SIZE], *ptr;
371 if (safe_sprintf(devpath, "%s/%s", conf->udev_dir, dev)) {
372 condlog(0, "devpath too small");
376 * Translate '!' into '/'
379 while ((ptr = strchr(ptr, '!'))) {
383 return open(devpath, mode);
387 do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
388 void *resp, int mx_resp_len)
390 unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
391 { INQUIRY_CMD, 0, 0, 0, 0, 0 };
392 unsigned char sense_b[SENSE_BUFF_LEN];
393 struct sg_io_hdr io_hdr;
399 inqCmdBlk[2] = (unsigned char) pg_op;
400 inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff);
401 inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff);
402 memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
403 memset(sense_b, 0, SENSE_BUFF_LEN);
404 io_hdr.interface_id = 'S';
405 io_hdr.cmd_len = sizeof (inqCmdBlk);
406 io_hdr.mx_sb_len = sizeof (sense_b);
407 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
408 io_hdr.dxfer_len = mx_resp_len;
409 io_hdr.dxferp = resp;
410 io_hdr.cmdp = inqCmdBlk;
411 io_hdr.sbp = sense_b;
412 io_hdr.timeout = DEF_TIMEOUT;
414 if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
417 /* treat SG_ERR here to get rid of sg_err.[ch] */
418 io_hdr.status &= 0x7e;
419 if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
420 (0 == io_hdr.driver_status))
422 if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
423 (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
424 (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
425 if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
427 unsigned char * sense_buffer = io_hdr.sbp;
428 if (sense_buffer[0] & 0x2)
429 sense_key = sense_buffer[1] & 0xf;
431 sense_key = sense_buffer[2] & 0xf;
432 if(RECOVERED_ERROR == sense_key)
440 get_serial (char * str, int maxlen, int fd)
443 char buff[MX_ALLOC_LEN + 1] = {0};
448 if (0 == do_inq(fd, 0, 1, 0x80, buff, MX_ALLOC_LEN)) {
453 memcpy(str, buff + 4, len);
462 get_inq (char * dev, char * vendor, char * product, char * rev, int fd)
464 unsigned char buff[MX_ALLOC_LEN + 1] = {0};
470 if (0 != do_inq(fd, 0, 0, 0, buff, MX_ALLOC_LEN))
473 /* Check peripheral qualifier */
474 if ((buff[0] >> 5) != 0) {
475 int pqual = (buff[0] >> 5);
478 condlog(3, "%s: INQUIRY failed, LU not connected", dev);
481 condlog(3, "%s: INQUIRY failed, LU not supported", dev);
484 condlog(3, "%s: INQUIRY failed, Invalid PQ %x",
495 condlog(3, "%s: INQUIRY response too short (len %d)",
501 memset(vendor, 0x0, 8);
502 memcpy(vendor, buff + 8, len > 8 ? 8 : len);
510 memset(product, 0x0, 16);
511 memcpy(product, buff + 16, len > 16 ? 16 : len);
520 memcpy(rev, buff + 32, 4);
528 get_geometry(struct path *pp)
533 if (ioctl(pp->fd, HDIO_GETGEO, &pp->geom)) {
534 condlog(2, "%s: HDIO_GETGEO failed with %d", pp->dev, errno);
535 memset(&pp->geom, 0, sizeof(pp->geom));
538 condlog(3, "%s: %u cyl, %u heads, %u sectors/track, start at %lu",
539 pp->dev, pp->geom.cylinders, pp->geom.heads,
540 pp->geom.sectors, pp->geom.start);
545 scsi_sysfs_pathinfo (struct path * pp, struct sysfs_device * parent)
547 char attr_path[FILE_NAME_SIZE];
549 if (sysfs_get_vendor(parent, pp->vendor_id, SCSI_VENDOR_SIZE))
552 condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
554 if (sysfs_get_model(parent, pp->product_id, SCSI_PRODUCT_SIZE))
557 condlog(3, "%s: product = %s", pp->dev, pp->product_id);
559 if (sysfs_get_rev(parent, pp->rev, SCSI_REV_SIZE))
562 condlog(3, "%s: rev = %s", pp->dev, pp->rev);
565 * set the hwe configlet pointer
567 pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, pp->rev);
570 * host / bus / target / lun
572 basenamecpy(parent->devpath, attr_path, FILE_NAME_SIZE);
574 sscanf(attr_path, "%i:%i:%i:%i",
579 condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
589 if(!sysfs_get_tgt_nodename(parent, pp->tgt_node_name,
592 pp->sg_id.scsi_id)) {
593 condlog(3, "%s: tgt_node_name = %s",
594 pp->dev, pp->tgt_node_name);
601 ccw_sysfs_pathinfo (struct path * pp, struct sysfs_device * parent)
603 char attr_path[FILE_NAME_SIZE];
604 char attr_buff[FILE_NAME_SIZE];
606 sprintf(pp->vendor_id, "IBM");
608 condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
610 if (sysfs_get_devtype(parent, attr_buff, FILE_NAME_SIZE))
613 if (!strncmp(attr_buff, "3370", 4)) {
614 sprintf(pp->product_id,"S/390 DASD FBA");
615 } else if (!strncmp(attr_buff, "9336", 4)) {
616 sprintf(pp->product_id,"S/390 DASD FBA");
618 sprintf(pp->product_id,"S/390 DASD ECKD");
621 condlog(3, "%s: product = %s", pp->dev, pp->product_id);
624 * set the hwe configlet pointer
626 pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, NULL);
629 * host / bus / target / lun
631 basenamecpy(parent->devpath, attr_path, FILE_NAME_SIZE);
633 sscanf(attr_path, "%i.%i.%x",
637 condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
648 cciss_sysfs_pathinfo (struct path * pp, struct sysfs_device * dev)
650 char attr_path[FILE_NAME_SIZE];
653 * host / bus / target / lun
655 basenamecpy(dev->devpath, attr_path, FILE_NAME_SIZE);
657 pp->sg_id.channel = 0;
658 sscanf(attr_path, "cciss!c%id%i",
661 condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
671 common_sysfs_pathinfo (struct path * pp, struct sysfs_device *dev)
675 len = sysfs_attr_get_value(dev->devpath, "dev",
676 pp->dev_t, BLK_DEV_SIZE);
678 condlog(3, "%s: no 'dev' attribute in sysfs", pp->dev);
682 condlog(3, "%s: dev_t = %s", pp->dev, pp->dev_t);
684 if (sysfs_get_size(dev, &pp->size))
687 condlog(3, "%s: size = %llu", pp->dev, pp->size);
692 struct sysfs_device *sysfs_device_from_path(struct path *pp)
694 char sysdev[FILE_NAME_SIZE];
696 if (pp->sysdev && sysfs_device_verify(pp->sysdev))
699 strlcpy(sysdev,"/block/", FILE_NAME_SIZE);
700 strlcat(sysdev,pp->dev, FILE_NAME_SIZE);
702 return sysfs_device_get(sysdev);
706 path_offline (struct path * pp)
708 struct sysfs_device * parent;
709 char buff[SCSI_STATE_SIZE];
711 if (pp->bus != SYSFS_BUS_SCSI)
714 pp->sysdev = sysfs_device_from_path(pp);
716 condlog(1, "%s: failed to get sysfs information", pp->dev);
720 parent = sysfs_device_get_parent(pp->sysdev);
723 if (parent && !strncmp(parent->kernel, "block",5))
724 parent = sysfs_device_get_parent(parent);
726 condlog(1, "%s: failed to get parent", pp->dev);
730 if (sysfs_get_state(parent, buff, SCSI_STATE_SIZE))
733 condlog(3, "%s: path state = %s", pp->dev, buff);
735 if (!strncmp(buff, "offline", 7)) {
740 if (!strncmp(buff, "blocked", 7))
742 else if (!strncmp(buff, "running", 7))
749 sysfs_pathinfo(struct path * pp)
751 struct sysfs_device *parent;
753 pp->sysdev = sysfs_device_from_path(pp);
755 condlog(1, "%s: failed to get sysfs information", pp->dev);
759 if (common_sysfs_pathinfo(pp, pp->sysdev))
762 parent = sysfs_device_get_parent(pp->sysdev);
765 if (parent && !strncmp(parent->kernel, "block",5))
766 parent = sysfs_device_get_parent(parent);
768 condlog(1, "%s: failed to get parent", pp->dev);
772 pp->bus = SYSFS_BUS_UNDEF;
773 if (!strncmp(pp->dev,"cciss",5))
774 pp->bus = SYSFS_BUS_CCISS;
775 if (!strncmp(pp->dev,"dasd", 4))
776 pp->bus = SYSFS_BUS_CCW;
777 if (!strncmp(pp->dev,"sd", 2))
778 pp->bus = SYSFS_BUS_SCSI;
780 if (pp->bus == SYSFS_BUS_UNDEF)
782 else if (pp->bus == SYSFS_BUS_SCSI) {
783 if (scsi_sysfs_pathinfo(pp, parent))
785 } else if (pp->bus == SYSFS_BUS_CCW) {
786 if (ccw_sysfs_pathinfo(pp, parent))
788 } else if (pp->bus == SYSFS_BUS_CCISS) {
789 if (cciss_sysfs_pathinfo(pp, pp->sysdev))
796 scsi_ioctl_pathinfo (struct path * pp, int mask)
798 if (mask & DI_SERIAL) {
799 get_serial(pp->serial, SERIAL_SIZE, pp->fd);
800 condlog(3, "%s: serial = %s", pp->dev, pp->serial);
807 cciss_ioctl_pathinfo (struct path * pp, int mask)
811 if (mask & DI_SYSFS) {
812 ret = get_inq(pp->dev, pp->vendor_id, pp->product_id,
817 condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
818 condlog(3, "%s: product = %s", pp->dev, pp->product_id);
819 condlog(3, "%s: revision = %s", pp->dev, pp->rev);
821 * set the hwe configlet pointer
823 pp->hwe = find_hwe(conf->hwtable, pp->vendor_id,
824 pp->product_id, pp->rev);
831 get_state (struct path * pp, int daemon)
833 struct checker * c = &pp->checker;
836 condlog(3, "%s: get_state", pp->dev);
838 if (!checker_selected(c)) {
839 if (daemon || pp->sysdev == NULL) {
840 if (pathinfo(pp, conf->hwtable, DI_SYSFS) != 0) {
841 condlog(3, "%s: couldn't get sysfs pathinfo",
843 return PATH_UNCHECKED;
847 if (!checker_selected(c)) {
848 condlog(3, "%s: No checker selected", pp->dev);
849 return PATH_UNCHECKED;
851 checker_set_fd(c, pp->fd);
852 if (checker_init(c, pp->mpp?&pp->mpp->mpcontext:NULL)) {
853 condlog(3, "%s: checker init failed", pp->dev);
854 return PATH_UNCHECKED;
857 checker_clear_message(c);
859 checker_set_async(c);
860 if (!conf->checker_timeout)
861 sysfs_get_timeout(pp->sysdev, &(c->timeout));
862 state = checker_check(c);
863 condlog(3, "%s: state = %s", pp->dev, checker_state_name(state));
864 if (state == PATH_DOWN && strlen(checker_message(c)))
865 condlog(3, "%s: checker msg is \"%s\"",
866 pp->dev, checker_message(c));
871 get_prio (struct path * pp)
879 condlog(3, "%s: no prio selected", pp->dev);
883 pp->priority = prio_getprio(pp->prio, pp);
884 if (pp->priority < 0) {
885 condlog(3, "%s: %s prio error", pp->dev, prio_name(pp->prio));
886 pp->priority = PRIO_UNDEF;
889 condlog(3, "%s: %s prio = %u",
890 pp->dev, prio_name(pp->prio), pp->priority);
895 get_uid (struct path * pp)
897 char buff[CALLOUT_MAX_SIZE], *c;
902 if (apply_format(pp->getuid, &buff[0], pp)) {
903 condlog(0, "error formatting uid callout command");
904 memset(pp->wwid, 0, WWID_SIZE);
905 } else if (execute_program(buff, pp->wwid, WWID_SIZE)) {
906 condlog(3, "error calling out %s", buff);
907 memset(pp->wwid, 0, WWID_SIZE);
910 /* Strip any trailing blanks */
911 c = strchr(pp->wwid, '\0');
913 while (c && c >= pp->wwid && *c == ' ') {
917 condlog(3, "%s: uid = %s (callout)", pp->dev,
918 *pp->wwid == '\0' ? "<empty>" : pp->wwid);
923 pathinfo (struct path *pp, vector hwtable, int mask)
927 condlog(3, "%s: mask = 0x%x", pp->dev, mask);
930 * fetch info available in sysfs
932 if (mask & DI_SYSFS && sysfs_pathinfo(pp))
935 path_state = path_offline(pp);
938 * fetch info not available through sysfs
941 pp->fd = opennode(pp->dev, O_RDWR);
944 condlog(4, "Couldn't open node for %s: %s",
945 pp->dev, strerror(errno));
949 if (mask & DI_SERIAL)
952 if (path_state == PATH_UP && pp->bus == SYSFS_BUS_SCSI &&
953 scsi_ioctl_pathinfo(pp, mask))
956 if (pp->bus == SYSFS_BUS_CCISS &&
957 cciss_ioctl_pathinfo(pp, mask))
960 if (mask & DI_CHECKER) {
961 if (path_state == PATH_UP) {
962 pp->state = get_state(pp, 0);
963 if (pp->state == PATH_UNCHECKED ||
964 pp->state == PATH_WILD)
967 condlog(3, "%s: path inaccessible", pp->dev);
968 pp->state = path_state;
973 * Retrieve path priority, even for PATH_DOWN paths if it has never
974 * been successfully obtained before.
976 if ((mask & DI_PRIO) && path_state == PATH_UP) {
977 if (pp->state != PATH_DOWN || pp->priority == PRIO_UNDEF) {
978 if (!strlen(pp->wwid))
982 pp->priority = PRIO_UNDEF;
986 if (path_state == PATH_UP && (mask & DI_WWID) && !strlen(pp->wwid))
993 * Recoverable error, for example faulty or offline path
995 memset(pp->wwid, 0, WWID_SIZE);
996 pp->state = PATH_DOWN;