2 * Copyright (c) 2004, 2005, 2006 Christophe Varoqui
3 * Copyright (c) 2005 Stefan Bader, IBM
4 * Copyright (c) 2005 Mike Anderson
20 #include "blacklist.h"
24 #include "sg_include.h"
26 #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 (filter_devnode(conf->blist_devnode, conf->elist_devnode,
68 if(safe_sprintf(path, "%s/block/%s/device", sysfs_path,
70 condlog(0, "path too small");
74 if (strncmp(devname,"cciss",5) && !filepresent(path)) {
75 condlog(4, "path %s not present", path);
79 pp = find_path_by_dev(pathvec, devname);
82 pp = store_pathinfo(pathvec, conf->hwtable,
86 return pathinfo(pp, conf->hwtable, flag);
90 path_discovery (vector pathvec, struct config * conf, int flag)
93 struct dirent *blkdev;
95 char devpath[PATH_MAX];
99 if (!(blkdir = opendir("/sys/block")))
102 strcpy(devpath,"/sys/block");
103 while ((blkdev = readdir(blkdir)) != NULL) {
104 if ((strcmp(blkdev->d_name,".") == 0) ||
105 (strcmp(blkdev->d_name,"..") == 0))
108 devptr = devpath + 10;
111 strcat(devptr,blkdev->d_name);
112 if (stat(devpath, &statbuf) < 0)
115 if (S_ISDIR(statbuf.st_mode) == 0)
118 condlog(4, "Discover device %s", devpath);
120 r += path_discover(pathvec, conf, blkdev->d_name, flag);
123 condlog(4, "Discovery status %d", r);
127 #define declare_sysfs_get_str(fname) \
129 sysfs_get_##fname (struct sysfs_device * dev, char * buff, size_t len) \
133 attr = sysfs_attr_get_value(dev->devpath, #fname); \
136 if (strlcpy(buff, attr, len) != strlen(attr)) \
142 declare_sysfs_get_str(devtype);
143 declare_sysfs_get_str(cutype);
144 declare_sysfs_get_str(vendor);
145 declare_sysfs_get_str(model);
146 declare_sysfs_get_str(rev);
149 sysfs_get_dev (struct sysfs_device * dev, char * buff, size_t len)
153 attr = sysfs_attr_get_value(dev->devpath, "dev");
155 condlog(3, "%s: no 'dev' attribute in sysfs", dev->kernel);
158 if (strlcpy(buff, attr, len) != strlen(attr)) {
159 condlog(3, "%s: overflow in 'dev' attribute", dev->kernel);
166 sysfs_get_size (struct sysfs_device * dev, unsigned long long * size)
171 attr = sysfs_attr_get_value(dev->devpath, "size");
175 r = sscanf(attr, "%llu\n", size);
184 sysfs_get_fc_nodename (struct sysfs_device * dev, char * node,
185 unsigned int host, unsigned int channel,
188 char attr_path[SYSFS_PATH_SIZE], *attr;
190 if (safe_sprintf(attr_path,
191 "/class/fc_transport/target%i:%i:%i",
192 host, channel, target)) {
193 condlog(0, "attr_path too small");
197 attr = sysfs_attr_get_value(attr_path, "node_name");
199 strlcpy(node, attr, strlen(attr));
207 * udev might be slow creating node files : wait
210 opennode (char * dev, int mode)
212 char devpath[FILE_NAME_SIZE], *ptr;
214 if (safe_sprintf(devpath, "%s/%s", conf->udev_dir, dev)) {
215 condlog(0, "devpath too small");
219 * Translate '!' into '/'
222 while ((ptr = strchr(ptr, '!'))) {
226 return open(devpath, mode);
230 devt2devname (char *devname, char *devt)
233 unsigned int tmpmaj, tmpmin, major, minor;
234 char dev[FILE_NAME_SIZE];
235 char block_path[FILE_NAME_SIZE];
238 if (sscanf(devt, "%u:%u", &major, &minor) != 2) {
239 condlog(0, "Invalid device number %s", devt);
243 if ((fd = fopen("/proc/partitions", "r")) < 0) {
244 condlog(0, "Cannot open /proc/partitions");
249 int r = fscanf(fd,"%u %u %*d %s",&tmpmaj, &tmpmin, dev);
257 if ((major == tmpmaj) && (minor == tmpmin)) {
258 sprintf(block_path, "/sys/block/%s", dev);
264 if (strncmp(block_path,"/sys/block", 10))
267 if (stat(block_path, &statbuf) < 0) {
268 condlog(0, "No sysfs entry for %s\n", block_path);
272 if (S_ISDIR(statbuf.st_mode) == 0) {
273 condlog(0, "sysfs entry %s is not a directory\n", block_path);
280 do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
281 void *resp, int mx_resp_len, int noisy)
283 unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
284 { INQUIRY_CMD, 0, 0, 0, 0, 0 };
285 unsigned char sense_b[SENSE_BUFF_LEN];
286 struct sg_io_hdr io_hdr;
292 inqCmdBlk[2] = (unsigned char) pg_op;
293 inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff);
294 inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff);
295 memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
296 io_hdr.interface_id = 'S';
297 io_hdr.cmd_len = sizeof (inqCmdBlk);
298 io_hdr.mx_sb_len = sizeof (sense_b);
299 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
300 io_hdr.dxfer_len = mx_resp_len;
301 io_hdr.dxferp = resp;
302 io_hdr.cmdp = inqCmdBlk;
303 io_hdr.sbp = sense_b;
304 io_hdr.timeout = DEF_TIMEOUT;
306 if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
309 /* treat SG_ERR here to get rid of sg_err.[ch] */
310 io_hdr.status &= 0x7e;
311 if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
312 (0 == io_hdr.driver_status))
314 if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
315 (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
316 (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
317 if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
319 unsigned char * sense_buffer = io_hdr.sbp;
320 if (sense_buffer[0] & 0x2)
321 sense_key = sense_buffer[1] & 0xf;
323 sense_key = sense_buffer[2] & 0xf;
324 if(RECOVERED_ERROR == sense_key)
332 get_serial (char * str, int maxlen, int fd)
335 char buff[MX_ALLOC_LEN + 1] = {0};
340 if (0 == do_inq(fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) {
345 memcpy(str, buff + 4, len);
354 get_inq (char * vendor, char * product, char * rev, int fd)
356 char buff[MX_ALLOC_LEN + 1] = {0};
361 if (0 == do_inq(fd, 0, 0, 0, buff, MX_ALLOC_LEN, 0)) {
362 memcpy(vendor, buff + 8, 8);
365 memcpy(product, buff + 16, 16);
368 memcpy(rev, buff + 32, 4);
377 scsi_sysfs_pathinfo (struct path * pp, struct sysfs_device * parent)
379 char attr_path[FILE_NAME_SIZE];
381 if (sysfs_get_vendor(parent, pp->vendor_id, SCSI_VENDOR_SIZE))
384 condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
386 if (sysfs_get_model(parent, pp->product_id, SCSI_PRODUCT_SIZE))
389 condlog(3, "%s: product = %s", pp->dev, pp->product_id);
391 if (sysfs_get_rev(parent, pp->rev, SCSI_REV_SIZE))
394 condlog(3, "%s: rev = %s", pp->dev, pp->rev);
397 * set the hwe configlet pointer
399 pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, pp->rev);
402 * host / bus / target / lun
404 basename(parent->devpath, attr_path);
406 sscanf(attr_path, "%i:%i:%i:%i",
411 condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
421 if(!sysfs_get_fc_nodename(parent, pp->tgt_node_name,
424 pp->sg_id.scsi_id)) {
425 condlog(3, "%s: tgt_node_name = %s",
426 pp->dev, pp->tgt_node_name);
433 ccw_sysfs_pathinfo (struct path * pp, struct sysfs_device * parent)
435 char attr_path[FILE_NAME_SIZE];
436 char attr_buff[FILE_NAME_SIZE];
438 sprintf(pp->vendor_id, "IBM");
440 condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
442 if (sysfs_get_devtype(parent, attr_buff, FILE_NAME_SIZE))
445 if (!strncmp(attr_buff, "3370", 4)) {
446 sprintf(pp->product_id,"S/390 DASD FBA");
447 } else if (!strncmp(attr_buff, "9336", 4)) {
448 sprintf(pp->product_id,"S/390 DASD FBA");
450 sprintf(pp->product_id,"S/390 DASD ECKD");
453 condlog(3, "%s: product = %s", pp->dev, pp->product_id);
456 * set the hwe configlet pointer
458 pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, NULL);
461 * host / bus / target / lun
463 basename(parent->devpath, attr_path);
465 sscanf(attr_path, "%i.%i.%x",
469 condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
480 cciss_sysfs_pathinfo (struct path * pp, struct sysfs_device * dev)
482 char attr_path[FILE_NAME_SIZE];
485 * host / bus / target / lun
487 basename(dev->devpath, attr_path);
489 pp->sg_id.channel = 0;
490 sscanf(attr_path, "cciss!c%id%i",
493 condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
503 common_sysfs_pathinfo (struct path * pp, struct sysfs_device *dev)
507 attr = sysfs_attr_get_value(dev->devpath, "dev");
509 condlog(3, "%s: no 'dev' attribute in sysfs", pp->dev);
512 strlcpy(pp->dev_t, attr, BLK_DEV_SIZE);
514 condlog(3, "%s: dev_t = %s", pp->dev, pp->dev_t);
516 if (sysfs_get_size(dev, &pp->size))
519 condlog(3, "%s: size = %llu", pp->dev, pp->size);
524 struct sysfs_device *sysfs_device_from_path(struct path *pp)
526 char sysdev[FILE_NAME_SIZE];
528 strlcpy(sysdev,"/block/", FILE_NAME_SIZE);
529 strlcat(sysdev,pp->dev, FILE_NAME_SIZE);
531 return sysfs_device_get(sysdev);
535 sysfs_pathinfo(struct path * pp)
537 struct sysfs_device *parent;
539 pp->sysdev = sysfs_device_from_path(pp);
541 condlog(1, "%s: failed to get sysfs information", pp->dev);
545 if (common_sysfs_pathinfo(pp, pp->sysdev))
548 parent = sysfs_device_get_parent(pp->sysdev);
552 if (!strncmp(parent->kernel, "block",5))
553 parent = sysfs_device_get_parent(parent);
555 condlog(3, "%s: subsystem = %s", pp->dev, parent->subsystem);
557 if (!strncmp(parent->subsystem, "scsi",4))
558 pp->bus = SYSFS_BUS_SCSI;
559 if (!strncmp(parent->subsystem, "ccw",3))
560 pp->bus = SYSFS_BUS_CCW;
561 if (!strncmp(pp->dev,"cciss",5))
562 pp->bus = SYSFS_BUS_CCISS;
564 if (pp->bus == SYSFS_BUS_UNDEF)
566 else if (pp->bus == SYSFS_BUS_SCSI) {
567 if (scsi_sysfs_pathinfo(pp, parent))
569 } else if (pp->bus == SYSFS_BUS_CCW) {
570 if (ccw_sysfs_pathinfo(pp, parent))
572 } else if (pp->bus == SYSFS_BUS_CCISS) {
573 if (cciss_sysfs_pathinfo(pp, pp->sysdev))
580 scsi_ioctl_pathinfo (struct path * pp, int mask)
582 if (mask & DI_SERIAL) {
583 get_serial(pp->serial, SERIAL_SIZE, pp->fd);
584 condlog(3, "%s: serial = %s", pp->dev, pp->serial);
591 cciss_ioctl_pathinfo (struct path * pp, int mask)
593 if (mask & DI_SYSFS) {
594 get_inq(pp->vendor_id, pp->product_id, pp->rev, pp->fd);
595 condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
596 condlog(3, "%s: product = %s", pp->dev, pp->product_id);
597 condlog(3, "%s: revision = %s", pp->dev, pp->rev);
599 * set the hwe configlet pointer
601 pp->hwe = find_hwe(conf->hwtable, pp->vendor_id,
602 pp->product_id, pp->rev);
609 get_state (struct path * pp)
611 struct checker * c = &pp->checker;
616 if (!checker_selected(c)) {
618 if (!checker_selected(c))
620 checker_set_fd(c, pp->fd);
621 if (checker_init(c, &pp->mpp->mpcontext))
624 pp->state = checker_check(c);
625 condlog(3, "%s: state = %i", pp->dev, pp->state);
626 if (pp->state == PATH_DOWN && strlen(checker_message(c)))
627 condlog(3, "%s: checker msg is \"%s\"",
628 pp->dev, checker_message(c));
633 get_prio (struct path * pp)
643 pp->priority = prio_getprio(pp->prio, pp);
644 if (pp->priority < 0) {
645 condlog(3, "%s: %s prio error", pp->dev, prio_name(pp->prio));
646 pp->priority = PRIO_UNDEF;
649 condlog(3, "%s: %s prio = %u",
650 pp->dev, prio_name(pp->prio), pp->priority);
655 get_uid (struct path * pp)
657 char buff[CALLOUT_MAX_SIZE];
662 if (apply_format(pp->getuid, &buff[0], pp)) {
663 condlog(0, "error formatting uid callout command");
664 memset(pp->wwid, 0, WWID_SIZE);
665 } else if (execute_program(buff, pp->wwid, WWID_SIZE)) {
666 condlog(3, "error calling out %s", buff);
667 memset(pp->wwid, 0, WWID_SIZE);
670 condlog(3, "%s: uid = %s (callout)", pp->dev ,pp->wwid);
675 pathinfo (struct path *pp, vector hwtable, int mask)
677 condlog(3, "%s: mask = 0x%x", pp->dev, mask);
680 * fetch info available in sysfs
682 if (mask & DI_SYSFS && sysfs_pathinfo(pp))
686 * fetch info not available through sysfs
689 pp->fd = opennode(pp->dev, O_RDONLY);
692 condlog(4, "Couldn't open node for %s: %s",
693 pp->dev, strerror(errno));
697 if (pp->bus == SYSFS_BUS_SCSI &&
698 scsi_ioctl_pathinfo(pp, mask))
701 if (pp->bus == SYSFS_BUS_CCISS &&
702 cciss_ioctl_pathinfo(pp, mask))
705 if (mask & DI_CHECKER && get_state(pp))
709 * Retrieve path priority, even for PATH_DOWN paths if it has never
710 * been successfully obtained before.
712 if (mask & DI_PRIO &&
713 (pp->state != PATH_DOWN || pp->priority == PRIO_UNDEF))
716 if (mask & DI_WWID && !strlen(pp->wwid))
723 * Recoverable error, for example faulty or offline path
725 memset(pp->wwid, 0, WWID_SIZE);
726 pp->state = PATH_DOWN;