2 * Copyright (c) 2004, 2005, 2006 Christophe Varoqui
3 * Copyright (c) 2005 Stefan Bader, IBM
4 * Copyright (c) 2005 Mike Anderson
22 #include "blacklist.h"
25 #include "sg_include.h"
27 #include "discovery.h"
32 store_pathinfo (vector pathvec, vector hwtable, struct udev_device *udevice,
33 int flag, struct path **pp_ptr)
42 devname = udev_device_get_sysname(udevice);
51 if(safe_sprintf(pp->dev, "%s", devname)) {
52 condlog(0, "pp->dev too small");
55 pp->udev = udev_device_ref(udevice);
56 err = pathinfo(pp, hwtable, flag | DI_BLACKLIST);
60 err = store_path(pathvec, pp);
73 path_discover (vector pathvec, struct config * conf,
74 struct udev_device *udevice, int flag)
79 devname = udev_device_get_sysname(udevice);
83 if (filter_devnode(conf->blist_devnode, conf->elist_devnode,
87 pp = find_path_by_dev(pathvec, (char *)devname);
89 if (store_pathinfo(pathvec, conf->hwtable,
90 udevice, flag, NULL) != 1)
95 return pathinfo(pp, conf->hwtable, flag);
99 path_discovery (vector pathvec, struct config * conf, int flag)
101 struct udev_enumerate *udev_iter;
102 struct udev_list_entry *entry;
103 struct udev_device *udevice;
107 udev_iter = udev_enumerate_new(conf->udev);
111 udev_enumerate_add_match_subsystem(udev_iter, "block");
112 udev_enumerate_scan_devices(udev_iter);
114 udev_list_entry_foreach(entry,
115 udev_enumerate_get_list_entry(udev_iter)) {
117 devpath = udev_list_entry_get_name(entry);
118 condlog(4, "Discover device %s", devpath);
119 udevice = udev_device_new_from_syspath(conf->udev, devpath);
121 condlog(4, "%s: no udev information", devpath);
125 devtype = udev_device_get_devtype(udevice);
126 if(devtype && !strncmp(devtype, "disk", 4))
127 r += path_discover(pathvec, conf, udevice, flag);
128 udev_device_unref(udevice);
130 udev_enumerate_unref(udev_iter);
131 condlog(4, "Discovery status %d", r);
135 #define declare_sysfs_get_str(fname) \
137 sysfs_get_##fname (struct udev_device * udev, char * buff, size_t len) \
140 const char * devname; \
142 devname = udev_device_get_sysname(udev); \
144 attr = udev_device_get_sysattr_value(udev, #fname); \
146 condlog(3, "%s: attribute %s not found in sysfs", \
150 if (strlen(attr) > len) { \
151 condlog(3, "%s: overflow in attribute %s", \
155 strlcpy(buff, attr, len); \
159 declare_sysfs_get_str(devtype);
160 declare_sysfs_get_str(cutype);
161 declare_sysfs_get_str(vendor);
162 declare_sysfs_get_str(model);
163 declare_sysfs_get_str(rev);
164 declare_sysfs_get_str(state);
165 declare_sysfs_get_str(dev);
168 sysfs_get_timeout(struct path *pp, unsigned int *timeout)
170 const char *attr = NULL;
172 struct udev_device *parent;
176 if (!pp->udev || pp->bus != SYSFS_BUS_SCSI)
181 subsys = udev_device_get_subsystem(parent);
182 attr = udev_device_get_sysattr_value(parent, "timeout");
185 parent = udev_device_get_parent(parent);
188 condlog(3, "%s: No timeout value in sysfs", pp->dev);
192 r = sscanf(attr, "%u\n", &t);
195 condlog(3, "%s: Cannot parse timeout attribute '%s'",
206 sysfs_get_tgt_nodename (struct path *pp, char * node)
208 const char *targetid, *value;
209 struct udev_device *parent, *tgtdev;
210 int host, channel, rport_id = -1, ata_id = -1;
212 parent = udev_device_get_parent_with_subsystem_devtype(pp->udev, "scsi", "scsi_device");
216 value = udev_device_get_sysattr_value(parent, "sas_address");
218 pp->sg_id.proto_id = SCSI_PROTOCOL_SAS;
219 strncpy(node, value, NODE_NAME_SIZE);
223 parent = udev_device_get_parent_with_subsystem_devtype(pp->udev, "scsi", "scsi_target");
226 /* Check for FibreChannel */
227 tgtdev = udev_device_get_parent(parent);
228 value = udev_device_get_sysname(tgtdev);
229 if (sscanf(value, "rport-%d:%d-%d",
230 &host, &channel, &rport_id) == 3) {
231 tgtdev = udev_device_new_from_subsystem_sysname(conf->udev,
232 "fc_remote_ports", value);
234 condlog(3, "SCSI target %d:%d:%d -> "
236 pp->sg_id.host_no, pp->sg_id.channel,
237 pp->sg_id.scsi_id, host, channel,
239 value = udev_device_get_sysattr_value(tgtdev,
242 pp->sg_id.proto_id = SCSI_PROTOCOL_FCP;
243 pp->sg_id.transport_id = rport_id;
244 strncpy(node, value, NODE_NAME_SIZE);
245 udev_device_unref(tgtdev);
248 udev_device_unref(tgtdev);
252 /* Check for iSCSI */
256 targetid = udev_device_get_sysname(parent);
257 if (!strncmp(targetid , "session", 6))
259 parent = udev_device_get_parent(parent);
263 tgtdev = udev_device_new_from_subsystem_sysname(conf->udev, "iscsi_session", targetid);
267 value = udev_device_get_sysattr_value(tgtdev, "targetname");
269 pp->sg_id.proto_id = SCSI_PROTOCOL_ISCSI;
270 strncpy(node, value, NODE_NAME_SIZE);
271 udev_device_unref(tgtdev);
275 udev_device_unref(tgtdev);
278 /* Check for libata */
282 targetid = udev_device_get_sysname(parent);
283 if (targetid && sscanf(targetid, "ata%d", &ata_id) == 1)
285 parent = udev_device_get_parent(parent);
289 pp->sg_id.proto_id = SCSI_PROTOCOL_ATA;
290 pp->sg_id.transport_id = ata_id;
291 snprintf(node, NODE_NAME_SIZE, "ata-%d.00", ata_id);
294 pp->sg_id.proto_id = SCSI_PROTOCOL_UNSPEC;
299 sysfs_set_rport_tmo(struct multipath *mpp, struct path *pp)
301 struct udev_device *rport_dev = NULL;
305 if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP) {
306 condlog(3, "%s: Not a FCP device", pp->dev);
309 sprintf(rport_id, "rport-%d:%d-%d",
310 pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id);
311 rport_dev = udev_device_new_from_subsystem_sysname(conf->udev,
312 "fc_remote_ports", rport_id);
314 condlog(1, "%s: No fc_remote_port device for '%s'", pp->dev,
318 condlog(4, "target%d:%d:%d -> %s", pp->sg_id.host_no,
319 pp->sg_id.channel, pp->sg_id.scsi_id, rport_id);
321 snprintf(value, 11, "%u", mpp->dev_loss);
323 sysfs_attr_set_value(rport_dev, "dev_loss_tmo", value, 11) <= 0) {
324 if ((mpp->fast_io_fail == MP_FAST_IO_FAIL_UNSET ||
325 mpp->fast_io_fail == MP_FAST_IO_FAIL_OFF)
326 && mpp->dev_loss > 600) {
327 condlog(3, "%s: limiting dev_loss_tmo to 600, since "
328 "fast_io_fail is not set", mpp->alias);
329 snprintf(value, 11, "%u", 600);
330 if (sysfs_attr_set_value(rport_dev, "dev_loss_tmo",
332 condlog(0, "%s failed to set dev_loss_tmo",
337 if (mpp->fast_io_fail != MP_FAST_IO_FAIL_UNSET){
338 if (mpp->fast_io_fail == MP_FAST_IO_FAIL_OFF)
339 sprintf(value, "off");
340 else if (mpp->fast_io_fail == MP_FAST_IO_FAIL_ZERO)
343 snprintf(value, 11, "%u", mpp->fast_io_fail);
344 if (sysfs_attr_set_value(rport_dev, "fast_io_fail_tmo",
346 condlog(0, "%s failed to set fast_io_fail_tmo",
351 udev_device_unref(rport_dev);
355 sysfs_set_scsi_tmo (struct multipath *mpp)
359 int dev_loss_tmo = mpp->dev_loss;
361 if (mpp->no_path_retry > 0) {
362 int no_path_retry_tmo = mpp->no_path_retry * conf->checkint;
364 if (no_path_retry_tmo > MAX_DEV_LOSS_TMO)
365 no_path_retry_tmo = MAX_DEV_LOSS_TMO;
366 if (no_path_retry_tmo > dev_loss_tmo)
367 dev_loss_tmo = no_path_retry_tmo;
368 condlog(3, "%s: update dev_loss_tmo to %d",
369 mpp->alias, dev_loss_tmo);
370 } else if (mpp->no_path_retry == NO_PATH_RETRY_QUEUE) {
371 dev_loss_tmo = MAX_DEV_LOSS_TMO;
372 condlog(3, "%s: update dev_loss_tmo to %d",
373 mpp->alias, dev_loss_tmo);
375 mpp->dev_loss = dev_loss_tmo;
376 if (mpp->dev_loss && mpp->fast_io_fail >= (int)mpp->dev_loss) {
377 condlog(3, "%s: turning off fast_io_fail (%d is not smaller than dev_loss_tmo)",
378 mpp->alias, mpp->fast_io_fail);
379 mpp->fast_io_fail = MP_FAST_IO_FAIL_OFF;
381 if (!mpp->dev_loss && mpp->fast_io_fail == MP_FAST_IO_FAIL_UNSET)
384 vector_foreach_slot(mpp->paths, pp, i) {
385 sysfs_set_rport_tmo(mpp, pp);
391 do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
392 void *resp, int mx_resp_len)
394 unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
395 { INQUIRY_CMD, 0, 0, 0, 0, 0 };
396 unsigned char sense_b[SENSE_BUFF_LEN];
397 struct sg_io_hdr io_hdr;
403 inqCmdBlk[2] = (unsigned char) pg_op;
404 inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff);
405 inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff);
406 memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
407 memset(sense_b, 0, SENSE_BUFF_LEN);
408 io_hdr.interface_id = 'S';
409 io_hdr.cmd_len = sizeof (inqCmdBlk);
410 io_hdr.mx_sb_len = sizeof (sense_b);
411 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
412 io_hdr.dxfer_len = mx_resp_len;
413 io_hdr.dxferp = resp;
414 io_hdr.cmdp = inqCmdBlk;
415 io_hdr.sbp = sense_b;
416 io_hdr.timeout = DEF_TIMEOUT;
418 if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
421 /* treat SG_ERR here to get rid of sg_err.[ch] */
422 io_hdr.status &= 0x7e;
423 if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
424 (0 == io_hdr.driver_status))
426 if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
427 (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
428 (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
429 if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
431 unsigned char * sense_buffer = io_hdr.sbp;
432 if (sense_buffer[0] & 0x2)
433 sense_key = sense_buffer[1] & 0xf;
435 sense_key = sense_buffer[2] & 0xf;
436 if(RECOVERED_ERROR == sense_key)
444 get_serial (char * str, int maxlen, int fd)
447 char buff[MX_ALLOC_LEN + 1] = {0};
452 if (0 == do_inq(fd, 0, 1, 0x80, buff, MX_ALLOC_LEN)) {
457 memcpy(str, buff + 4, len);
466 get_geometry(struct path *pp)
471 if (ioctl(pp->fd, HDIO_GETGEO, &pp->geom)) {
472 condlog(2, "%s: HDIO_GETGEO failed with %d", pp->dev, errno);
473 memset(&pp->geom, 0, sizeof(pp->geom));
476 condlog(3, "%s: %u cyl, %u heads, %u sectors/track, start at %lu",
477 pp->dev, pp->geom.cylinders, pp->geom.heads,
478 pp->geom.sectors, pp->geom.start);
483 scsi_sysfs_pathinfo (struct path * pp)
485 struct udev_device *parent;
486 const char *attr_path = NULL;
490 const char *subsys = udev_device_get_subsystem(parent);
491 if (subsys && !strncmp(subsys, "scsi", 4)) {
492 attr_path = udev_device_get_sysname(parent);
495 if (sscanf(attr_path, "%i:%i:%i:%i",
499 &pp->sg_id.lun) == 4)
502 parent = udev_device_get_parent(parent);
504 if (!attr_path || pp->sg_id.host_no == -1)
507 if (sysfs_get_vendor(parent, pp->vendor_id, SCSI_VENDOR_SIZE))
510 condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
512 if (sysfs_get_model(parent, pp->product_id, SCSI_PRODUCT_SIZE))
515 condlog(3, "%s: product = %s", pp->dev, pp->product_id);
517 if (sysfs_get_rev(parent, pp->rev, SCSI_REV_SIZE))
520 condlog(3, "%s: rev = %s", pp->dev, pp->rev);
523 * set the hwe configlet pointer
525 pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, pp->rev);
528 * host / bus / target / lun
530 condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
540 if(!sysfs_get_tgt_nodename(pp, pp->tgt_node_name)) {
541 condlog(3, "%s: tgt_node_name = %s",
542 pp->dev, pp->tgt_node_name);
549 ccw_sysfs_pathinfo (struct path * pp)
551 struct udev_device *parent;
552 char attr_buff[NAME_SIZE];
553 const char *attr_path;
557 const char *subsys = udev_device_get_subsystem(parent);
558 if (subsys && !strncmp(subsys, "ccw", 3))
560 parent = udev_device_get_parent(parent);
565 sprintf(pp->vendor_id, "IBM");
567 condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
569 if (sysfs_get_devtype(parent, attr_buff, FILE_NAME_SIZE))
572 if (!strncmp(attr_buff, "3370", 4)) {
573 sprintf(pp->product_id,"S/390 DASD FBA");
574 } else if (!strncmp(attr_buff, "9336", 4)) {
575 sprintf(pp->product_id,"S/390 DASD FBA");
577 sprintf(pp->product_id,"S/390 DASD ECKD");
580 condlog(3, "%s: product = %s", pp->dev, pp->product_id);
583 * set the hwe configlet pointer
585 pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, NULL);
588 * host / bus / target / lun
590 attr_path = udev_device_get_sysname(parent);
592 sscanf(attr_path, "%i.%i.%x",
596 condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
607 cciss_sysfs_pathinfo (struct path * pp)
609 const char * attr_path = NULL;
610 struct udev_device *parent;
614 const char *subsys = udev_device_get_subsystem(parent);
615 if (subsys && !strncmp(subsys, "cciss", 5)) {
616 attr_path = udev_device_get_sysname(parent);
619 if (sscanf(attr_path, "c%id%i",
621 &pp->sg_id.scsi_id) == 2)
624 parent = udev_device_get_parent(parent);
626 if (!attr_path || pp->sg_id.host_no == -1)
629 if (sysfs_get_vendor(parent, pp->vendor_id, SCSI_VENDOR_SIZE))
632 condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
634 if (sysfs_get_model(parent, pp->product_id, SCSI_PRODUCT_SIZE))
637 condlog(3, "%s: product = %s", pp->dev, pp->product_id);
639 if (sysfs_get_rev(parent, pp->rev, SCSI_REV_SIZE))
642 condlog(3, "%s: rev = %s", pp->dev, pp->rev);
645 * set the hwe configlet pointer
647 pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, pp->rev);
650 * host / bus / target / lun
653 pp->sg_id.channel = 0;
654 condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
664 common_sysfs_pathinfo (struct path * pp)
667 condlog(4, "%s: udev not initialised", pp->dev);
670 if (sysfs_get_dev(pp->udev, pp->dev_t, BLK_DEV_SIZE)) {
671 condlog(3, "%s: no 'dev' attribute in sysfs", pp->dev);
675 condlog(3, "%s: dev_t = %s", pp->dev, pp->dev_t);
677 if (sysfs_get_size(pp, &pp->size))
680 condlog(3, "%s: size = %llu", pp->dev, pp->size);
686 path_offline (struct path * pp)
688 struct udev_device * parent;
689 char buff[SCSI_STATE_SIZE];
691 if (pp->bus != SYSFS_BUS_SCSI)
696 const char *subsys = udev_device_get_subsystem(parent);
697 if (subsys && !strncmp(subsys, "scsi", 4))
699 parent = udev_device_get_parent(parent);
703 condlog(1, "%s: failed to get sysfs information", pp->dev);
707 if (sysfs_get_state(parent, buff, SCSI_STATE_SIZE))
710 condlog(3, "%s: path state = %s", pp->dev, buff);
712 if (!strncmp(buff, "offline", 7)) {
717 if (!strncmp(buff, "blocked", 7))
719 else if (!strncmp(buff, "running", 7))
726 sysfs_pathinfo(struct path * pp)
728 if (common_sysfs_pathinfo(pp))
731 pp->bus = SYSFS_BUS_UNDEF;
732 if (!strncmp(pp->dev,"cciss",5))
733 pp->bus = SYSFS_BUS_CCISS;
734 if (!strncmp(pp->dev,"dasd", 4))
735 pp->bus = SYSFS_BUS_CCW;
736 if (!strncmp(pp->dev,"sd", 2))
737 pp->bus = SYSFS_BUS_SCSI;
739 if (pp->bus == SYSFS_BUS_UNDEF)
741 else if (pp->bus == SYSFS_BUS_SCSI) {
742 if (scsi_sysfs_pathinfo(pp))
744 } else if (pp->bus == SYSFS_BUS_CCW) {
745 if (ccw_sysfs_pathinfo(pp))
747 } else if (pp->bus == SYSFS_BUS_CCISS) {
748 if (cciss_sysfs_pathinfo(pp))
755 scsi_ioctl_pathinfo (struct path * pp, int mask)
757 if (mask & DI_SERIAL) {
758 get_serial(pp->serial, SERIAL_SIZE, pp->fd);
759 condlog(3, "%s: serial = %s", pp->dev, pp->serial);
766 cciss_ioctl_pathinfo (struct path * pp, int mask)
768 if (mask & DI_SERIAL) {
769 get_serial(pp->serial, SERIAL_SIZE, pp->fd);
770 condlog(3, "%s: serial = %s", pp->dev, pp->serial);
776 get_state (struct path * pp, int daemon)
778 struct checker * c = &pp->checker;
781 condlog(3, "%s: get_state", pp->dev);
783 if (!checker_selected(c)) {
785 if (pathinfo(pp, conf->hwtable, DI_SYSFS) != 0) {
786 condlog(3, "%s: couldn't get sysfs pathinfo",
788 return PATH_UNCHECKED;
792 if (!checker_selected(c)) {
793 condlog(3, "%s: No checker selected", pp->dev);
794 return PATH_UNCHECKED;
796 checker_set_fd(c, pp->fd);
797 if (checker_init(c, pp->mpp?&pp->mpp->mpcontext:NULL)) {
798 memset(c, 0x0, sizeof(struct checker));
799 condlog(3, "%s: checker init failed", pp->dev);
800 return PATH_UNCHECKED;
803 checker_clear_message(c);
805 checker_set_async(c);
806 if (!conf->checker_timeout &&
807 (pp->bus != SYSFS_BUS_SCSI ||
808 sysfs_get_timeout(pp, &(c->timeout))))
809 c->timeout = DEF_TIMEOUT;
810 state = checker_check(c);
811 condlog(3, "%s: state = %s", pp->dev, checker_state_name(state));
812 if (state != PATH_UP && strlen(checker_message(c)))
813 condlog(3, "%s: checker msg is \"%s\"",
814 pp->dev, checker_message(c));
819 get_prio (struct path * pp)
824 struct prio * p = &pp->prio;
826 if (!prio_selected(p)) {
827 select_detect_prio(pp);
829 if (!prio_selected(p)) {
830 condlog(3, "%s: no prio selected", pp->dev);
834 pp->priority = prio_getprio(p, pp);
835 if (pp->priority < 0) {
836 condlog(3, "%s: %s prio error", pp->dev, prio_name(p));
837 pp->priority = PRIO_UNDEF;
840 condlog(3, "%s: %s prio = %u",
841 pp->dev, prio_name(p), pp->priority);
846 get_uid (struct path * pp)
851 if (!pp->uid_attribute)
855 condlog(1, "%s: no udev information", pp->dev);
859 memset(pp->wwid, 0, WWID_SIZE);
860 value = udev_device_get_property_value(pp->udev, pp->uid_attribute);
861 if ((!value || strlen(value) == 0) && conf->dry_run == 2)
862 value = getenv(pp->uid_attribute);
863 if (value && strlen(value)) {
864 size_t len = WWID_SIZE;
866 if (strlen(value) + 1 > WWID_SIZE) {
867 condlog(0, "%s: wwid overflow", pp->dev);
871 strncpy(pp->wwid, value, len);
873 condlog(3, "%s: no %s attribute", pp->dev,
877 /* Strip any trailing blanks */
878 c = strchr(pp->wwid, '\0');
880 while (c && c >= pp->wwid && *c == ' ') {
884 condlog(3, "%s: uid = %s (udev)", pp->dev,
885 *pp->wwid == '\0' ? "<empty>" : pp->wwid);
890 pathinfo (struct path *pp, vector hwtable, int mask)
894 condlog(3, "%s: mask = 0x%x", pp->dev, mask);
897 * fetch info available in sysfs
899 if (mask & DI_SYSFS && sysfs_pathinfo(pp))
902 if (mask & DI_BLACKLIST && mask & DI_SYSFS) {
903 if (filter_device(conf->blist_device, conf->elist_device,
904 pp->vendor_id, pp->product_id) > 0) {
909 path_state = path_offline(pp);
912 * fetch info not available through sysfs
915 pp->fd = open(udev_device_get_devnode(pp->udev), O_RDONLY);
918 condlog(4, "Couldn't open node for %s: %s",
919 pp->dev, strerror(errno));
923 if (mask & DI_SERIAL)
926 if (path_state == PATH_UP && pp->bus == SYSFS_BUS_SCSI &&
927 scsi_ioctl_pathinfo(pp, mask))
930 if (pp->bus == SYSFS_BUS_CCISS &&
931 cciss_ioctl_pathinfo(pp, mask))
934 if (mask & DI_CHECKER) {
935 if (path_state == PATH_UP) {
936 pp->chkrstate = pp->state = get_state(pp, 0);
937 if (pp->state == PATH_UNCHECKED ||
938 pp->state == PATH_WILD)
941 condlog(3, "%s: path inaccessible", pp->dev);
942 pp->chkrstate = pp->state = path_state;
946 if (path_state == PATH_UP && (mask & DI_WWID) && !strlen(pp->wwid))
948 if (mask & DI_BLACKLIST && mask & DI_WWID) {
949 if (filter_wwid(conf->blist_wwid, conf->elist_wwid,
956 * Retrieve path priority, even for PATH_DOWN paths if it has never
957 * been successfully obtained before.
959 if ((mask & DI_PRIO) && path_state == PATH_UP) {
960 if (pp->state != PATH_DOWN || pp->priority == PRIO_UNDEF) {
961 if (!strlen(pp->wwid))
965 pp->priority = PRIO_UNDEF;
973 * Recoverable error, for example faulty or offline path
975 memset(pp->wwid, 0, WWID_SIZE);
976 pp->chkrstate = pp->state = PATH_DOWN;