2 * Copyright (c) 2004, 2005, 2006 Christophe Varoqui
3 * Copyright (c) 2005 Stefan Bader, IBM
4 * Copyright (c) 2005 Mike Anderson
12 #include <sysfs/dlist.h>
13 #include <sysfs/libsysfs.h>
22 #include "blacklist.h"
26 #include "sg_include.h"
27 #include "discovery.h"
30 store_pathinfo (vector pathvec, vector hwtable, char * devname, int flag)
39 if(safe_sprintf(pp->dev, "%s", devname)) {
40 condlog(0, "pp->dev too small");
43 if (pathinfo(pp, hwtable, flag))
46 if (store_path(pathvec, pp))
56 path_discover (vector pathvec, struct config * conf, char * devname, int flag)
58 char path[FILE_NAME_SIZE];
64 if (blacklist(conf->blist_devnode, devname))
67 if(safe_sprintf(path, "%s/block/%s/device", sysfs_path,
69 condlog(0, "path too small");
73 if (!filepresent(path))
76 pp = find_path_by_dev(pathvec, devname);
79 pp = store_pathinfo(pathvec, conf->hwtable,
83 return pathinfo(pp, conf->hwtable, flag);
87 path_discovery (vector pathvec, struct config * conf, int flag)
90 struct sysfs_class * class;
91 struct sysfs_class_device * dev;
94 if (!(class = sysfs_open_class("block")))
97 if (!(ls = sysfs_get_class_devices(class)))
102 dlist_for_each_data(ls, dev, struct sysfs_class_device)
103 r += path_discover(pathvec, conf, dev->name, flag);
106 sysfs_close_class(class);
111 * the daemon can race udev upon path add,
112 * not multipath(8), ran by udev
115 #define WAIT_MAX_SECONDS 5
116 #define WAIT_LOOP_PER_SECOND 5
119 wait_for_file (char * filename)
124 loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND;
127 if (stat(filename, &stats) == 0)
133 usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
139 wait_for_file (char * filename)
145 #define declare_sysfs_get_str(fname, fmt) \
147 sysfs_get_##fname (char * sysfs_path, char * dev, char * buff, int len) \
149 struct sysfs_attribute * attr; \
150 char attr_path[SYSFS_PATH_SIZE]; \
152 if (safe_sprintf(attr_path, fmt, sysfs_path, dev)) \
155 if (wait_for_file(attr_path)) \
158 if (!(attr = sysfs_open_attribute(attr_path))) \
161 if (0 > sysfs_read_attribute(attr)) \
164 if (attr->len < 2 || attr->len - 1 > len) \
167 strncpy(buff, attr->value, attr->len - 1); \
168 buff[attr->len - 1] = '\0'; \
169 sysfs_close_attribute(attr); \
172 sysfs_close_attribute(attr); \
176 declare_sysfs_get_str(devtype, "%s/block/%s/device/devtype");
177 declare_sysfs_get_str(cutype, "%s/block/%s/device/cutype");
178 declare_sysfs_get_str(vendor, "%s/block/%s/device/vendor");
179 declare_sysfs_get_str(model, "%s/block/%s/device/model");
180 declare_sysfs_get_str(rev, "%s/block/%s/device/rev");
181 declare_sysfs_get_str(dev, "%s/block/%s/dev");
184 sysfs_get_size (char * sysfs_path, char * dev, unsigned long long * size)
186 struct sysfs_attribute * attr;
187 char attr_path[SYSFS_PATH_SIZE];
190 if (safe_sprintf(attr_path, "%s/block/%s/size", sysfs_path, dev))
193 attr = sysfs_open_attribute(attr_path);
198 if (0 > sysfs_read_attribute(attr))
201 r = sscanf(attr->value, "%llu\n", size);
202 sysfs_close_attribute(attr);
209 sysfs_close_attribute(attr);
214 * udev might be slow creating node files : wait
217 opennode (char * dev, int mode)
219 char devpath[FILE_NAME_SIZE];
221 if (safe_sprintf(devpath, "%s/%s", conf->udev_dir, dev)) {
222 condlog(0, "devpath too small");
226 if (wait_for_file(devpath)) {
227 condlog(3, "failed to open %s", devpath);
231 return open(devpath, mode);
235 devt2devname (char *devname, char *devt)
238 char attr_path[FILE_NAME_SIZE];
239 char block_path[FILE_NAME_SIZE];
240 struct sysfs_attribute * attr = NULL;
241 struct sysfs_class * class;
242 struct sysfs_class_device * dev;
244 if(safe_sprintf(block_path, "%s/block", sysfs_path)) {
245 condlog(0, "block_path too small");
248 if (!(class = sysfs_open_class("block")))
251 if (!(ls = sysfs_get_class_devices(class)))
254 dlist_for_each_data(ls, dev, struct sysfs_class_device) {
255 if(safe_sprintf(attr_path, "%s/%s/dev",
256 block_path, dev->name)) {
257 condlog(0, "attr_path too small");
260 if (!(attr = sysfs_open_attribute(attr_path)))
263 if (sysfs_read_attribute(attr))
266 /* discard newline */
267 if (attr->len > 1) attr->len--;
269 if (strlen(devt) == attr->len &&
270 strncmp(attr->value, devt, attr->len) == 0) {
271 if(safe_sprintf(attr_path, "%s/%s",
272 block_path, dev->name)) {
273 condlog(0, "attr_path too small");
276 sysfs_get_name_from_path(attr_path, devname,
278 sysfs_close_attribute(attr);
279 sysfs_close_class(class);
284 sysfs_close_attribute(attr);
286 sysfs_close_class(class);
291 do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
292 void *resp, int mx_resp_len, int noisy)
294 unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
295 { INQUIRY_CMD, 0, 0, 0, 0, 0 };
296 unsigned char sense_b[SENSE_BUFF_LEN];
297 struct sg_io_hdr io_hdr;
303 inqCmdBlk[2] = (unsigned char) pg_op;
304 inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff);
305 inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff);
306 memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
307 io_hdr.interface_id = 'S';
308 io_hdr.cmd_len = sizeof (inqCmdBlk);
309 io_hdr.mx_sb_len = sizeof (sense_b);
310 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
311 io_hdr.dxfer_len = mx_resp_len;
312 io_hdr.dxferp = resp;
313 io_hdr.cmdp = inqCmdBlk;
314 io_hdr.sbp = sense_b;
315 io_hdr.timeout = DEF_TIMEOUT;
317 if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
320 /* treat SG_ERR here to get rid of sg_err.[ch] */
321 io_hdr.status &= 0x7e;
322 if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
323 (0 == io_hdr.driver_status))
325 if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
326 (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
327 (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
328 if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
330 unsigned char * sense_buffer = io_hdr.sbp;
331 if (sense_buffer[0] & 0x2)
332 sense_key = sense_buffer[1] & 0xf;
334 sense_key = sense_buffer[2] & 0xf;
335 if(RECOVERED_ERROR == sense_key)
343 get_serial (char * str, int fd)
346 char buff[MX_ALLOC_LEN + 1] = {0};
351 if (0 == do_inq(fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) {
354 memcpy(str, buff + 4, len);
363 sysfs_get_bus (char * sysfs_path, struct path * pp)
365 struct sysfs_device *sdev;
366 char attr_path[FILE_NAME_SIZE];
367 char attr_buff[FILE_NAME_SIZE];
369 pp->bus = SYSFS_BUS_UNDEF;
372 * This is ugly : we should be able to do a simple
373 * get_link("%s/block/%s/device/bus", ...) but it just
376 if(safe_sprintf(attr_path, "%s/block/%s/device",
377 sysfs_path, pp->dev)) {
378 condlog(0, "attr_path too small");
382 if (0 > sysfs_get_link(attr_path, attr_buff, sizeof(attr_buff)))
386 int loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND;
389 sdev = sysfs_open_device_path(attr_buff);
391 if (strlen(sdev->bus))
394 sysfs_close_device(sdev);
395 usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
398 sdev = sysfs_open_device_path(attr_buff);
401 if (!strncmp(sdev->bus, "scsi", 4))
402 pp->bus = SYSFS_BUS_SCSI;
403 else if (!strncmp(sdev->bus, "ide", 3))
404 pp->bus = SYSFS_BUS_IDE;
405 else if (!strncmp(sdev->bus, "ccw", 3))
406 pp->bus = SYSFS_BUS_CCW;
410 sysfs_close_device(sdev);
416 scsi_sysfs_pathinfo (struct path * pp)
418 char attr_path[FILE_NAME_SIZE];
419 char attr_buff[FILE_NAME_SIZE];
420 struct sysfs_attribute * attr;
422 if (sysfs_get_vendor(sysfs_path, pp->dev,
423 pp->vendor_id, SCSI_VENDOR_SIZE))
426 condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
428 if (sysfs_get_model(sysfs_path, pp->dev,
429 pp->product_id, SCSI_PRODUCT_SIZE))
432 condlog(3, "%s: product = %s", pp->dev, pp->product_id);
434 if (sysfs_get_rev(sysfs_path, pp->dev,
435 pp->rev, SCSI_REV_SIZE))
438 condlog(3, "%s: rev = %s", pp->dev, pp->rev);
441 * set the hwe configlet pointer
443 pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id);
446 * host / bus / target / lun
448 if(safe_sprintf(attr_path, "%s/block/%s/device",
449 sysfs_path, pp->dev)) {
450 condlog(0, "attr_path too small");
453 if (0 > sysfs_get_link(attr_path, attr_buff, sizeof(attr_buff)))
456 basename(attr_buff, attr_path);
458 sscanf(attr_path, "%i:%i:%i:%i",
463 condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
473 if(safe_sprintf(attr_path,
474 "%s/class/fc_transport/target%i:%i:%i/node_name",
478 pp->sg_id.scsi_id)) {
479 condlog(0, "attr_path too small");
482 if (!(attr = sysfs_open_attribute(attr_path)))
485 if (sysfs_read_attribute(attr))
489 strncpy(pp->tgt_node_name, attr->value, attr->len - 1);
491 condlog(3, "%s: tgt_node_name = %s",
492 pp->dev, pp->tgt_node_name);
496 sysfs_close_attribute(attr);
501 ccw_sysfs_pathinfo (struct path * pp)
503 char attr_path[FILE_NAME_SIZE];
504 char attr_buff[FILE_NAME_SIZE];
506 sprintf(pp->vendor_id, "IBM");
508 condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
510 if (sysfs_get_devtype(sysfs_path, pp->dev,
511 attr_buff, FILE_NAME_SIZE))
514 if (!strncmp(attr_buff, "3370", 4)) {
515 sprintf(pp->product_id,"S/390 DASD FBA");
516 } else if (!strncmp(attr_buff, "9336", 4)) {
517 sprintf(pp->product_id,"S/390 DASD FBA");
519 sprintf(pp->product_id,"S/390 DASD ECKD");
522 condlog(3, "%s: product = %s", pp->dev, pp->product_id);
525 * set the hwe configlet pointer
527 pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id);
530 * host / bus / target / lun
532 if(safe_sprintf(attr_path, "%s/block/%s/device",
533 sysfs_path, pp->dev)) {
534 condlog(0, "attr_path too small");
537 if (0 > sysfs_get_link(attr_path, attr_buff, sizeof(attr_buff)))
540 basename(attr_buff, attr_path);
542 sscanf(attr_path, "%i.%i.%x",
546 condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
557 common_sysfs_pathinfo (struct path * pp)
559 if (sysfs_get_bus(sysfs_path, pp))
562 condlog(3, "%s: bus = %i", pp->dev, pp->bus);
564 if (sysfs_get_dev(sysfs_path, pp->dev,
565 pp->dev_t, BLK_DEV_SIZE))
568 condlog(3, "%s: dev_t = %s", pp->dev, pp->dev_t);
570 if (sysfs_get_size(sysfs_path, pp->dev, &pp->size))
573 condlog(3, "%s: size = %llu", pp->dev, pp->size);
579 sysfs_pathinfo(struct path * pp)
581 if (common_sysfs_pathinfo(pp))
584 if (pp->bus == SYSFS_BUS_UNDEF)
586 else if (pp->bus == SYSFS_BUS_SCSI) {
587 if (scsi_sysfs_pathinfo(pp))
589 } else if (pp->bus == SYSFS_BUS_CCW) {
590 if (ccw_sysfs_pathinfo(pp))
597 scsi_ioctl_pathinfo (struct path * pp, int mask)
599 if (mask & DI_SERIAL) {
600 get_serial(pp->serial, pp->fd);
601 condlog(3, "%s: serial = %s", pp->dev, pp->serial);
608 get_state (struct path * pp)
610 struct checker * c = &pp->checker;
612 if (!checker_selected(c)) {
614 if (!checker_selected(c))
616 checker_set_fd(c, pp->fd);
620 pp->state = checker_check(c);
621 condlog(3, "%s: state = %i", pp->dev, pp->state);
622 if (pp->state == PATH_DOWN)
623 condlog(2, "%s: checker msg is \"%s\"",
624 pp->dev, checker_message(c));
629 get_prio (struct path * pp)
631 char buff[CALLOUT_MAX_SIZE];
634 if (!pp->getprio_selected) {
636 pp->getprio_selected = 1;
640 } else if (apply_format(pp->getprio, &buff[0], pp)) {
641 condlog(0, "error formatting prio callout command");
644 } else if (execute_program(buff, prio, 16)) {
645 condlog(0, "error calling out %s", buff);
649 pp->priority = atoi(prio);
651 condlog(3, "%s: prio = %u", pp->dev, pp->priority);
656 get_uid (struct path * pp)
658 char buff[CALLOUT_MAX_SIZE];
663 if (apply_format(pp->getuid, &buff[0], pp)) {
664 condlog(0, "error formatting uid callout command");
665 memset(pp->wwid, 0, WWID_SIZE);
666 } else if (execute_program(buff, pp->wwid, WWID_SIZE)) {
667 condlog(0, "error calling out %s", buff);
668 memset(pp->wwid, 0, WWID_SIZE);
671 condlog(3, "%s: uid = %s (callout)", pp->dev ,pp->wwid);
676 pathinfo (struct path *pp, vector hwtable, int mask)
678 condlog(3, "%s: mask = 0x%x", pp->dev, mask);
681 * fetch info available in sysfs
683 if (mask & DI_SYSFS && sysfs_pathinfo(pp))
687 * fetch info not available through sysfs
690 pp->fd = opennode(pp->dev, O_RDONLY);
695 if (pp->bus == SYSFS_BUS_SCSI &&
696 scsi_ioctl_pathinfo(pp, mask))
699 if (mask & DI_CHECKER && get_state(pp))
702 if (mask & DI_PRIO && pp->state != PATH_DOWN)
705 if (mask & DI_WWID && !strlen(pp->wwid))
712 * Recoverable error, for example faulty or offline path
714 memset(pp->wwid, 0, WWID_SIZE);
715 pp->state = PATH_DOWN;