diff options
author | Andrew Patterson <andrew.patterson@hp.com> | 2009-06-02 08:48:39 -0400 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2009-06-02 08:48:39 -0400 |
commit | 7fe063268e73681cdca1a6496a25f93d3332f517 (patch) | |
tree | 97c9b5f53012908343af83c481c0b8fad888690e /drivers/block/cciss.c | |
parent | 88f627ae394eadd75ada669904269f1a4a77b3bd (diff) |
cciss: add cciss driver sysfs entries
Add sysfs entries to the cciss driver needed for the dm/multipath tools.
A file for vendor, model, rev, and unique_id is added for each logical
drive under directory /sys/bus/pci/devices/<dev>/ccissX/cXdY. Where X =
the controller (or host) number and Y is the logical drive number.
A link from /sys/bus/pci/devices/<dev>/ccissX/cXdY/block:cciss!cXdY to
/sys/block/cciss!cXdY/device is also created. A bus is created in
/sys/bus/cciss. A link is created from the pci ccissX entry to
/sys/bus/cciss/devices/ccissX. Please consider this for inclusion.
Signed-off-by: Mike Miller <mike.miller@hp.com>
Cc: Stephen M. Cameron <scameron@beardog.cca.cpqcorp.net>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'drivers/block/cciss.c')
-rw-r--r-- | drivers/block/cciss.c | 267 |
1 files changed, 264 insertions, 3 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index cb43fb3af159..e7d00952dd4f 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
@@ -437,6 +437,194 @@ static void __devinit cciss_procinit(int i) | |||
437 | } | 437 | } |
438 | #endif /* CONFIG_PROC_FS */ | 438 | #endif /* CONFIG_PROC_FS */ |
439 | 439 | ||
440 | #define MAX_PRODUCT_NAME_LEN 19 | ||
441 | |||
442 | #define to_hba(n) container_of(n, struct ctlr_info, dev) | ||
443 | #define to_drv(n) container_of(n, drive_info_struct, dev) | ||
444 | |||
445 | static struct device_type cciss_host_type = { | ||
446 | .name = "cciss_host", | ||
447 | }; | ||
448 | |||
449 | static ssize_t dev_show_unique_id(struct device *dev, | ||
450 | struct device_attribute *attr, | ||
451 | char *buf) | ||
452 | { | ||
453 | drive_info_struct *drv = to_drv(dev); | ||
454 | struct ctlr_info *h = to_hba(drv->dev.parent); | ||
455 | __u8 sn[16]; | ||
456 | unsigned long flags; | ||
457 | int ret = 0; | ||
458 | |||
459 | spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); | ||
460 | if (h->busy_configuring) | ||
461 | ret = -EBUSY; | ||
462 | else | ||
463 | memcpy(sn, drv->serial_no, sizeof(sn)); | ||
464 | spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); | ||
465 | |||
466 | if (ret) | ||
467 | return ret; | ||
468 | else | ||
469 | return snprintf(buf, 16 * 2 + 2, | ||
470 | "%02X%02X%02X%02X%02X%02X%02X%02X" | ||
471 | "%02X%02X%02X%02X%02X%02X%02X%02X\n", | ||
472 | sn[0], sn[1], sn[2], sn[3], | ||
473 | sn[4], sn[5], sn[6], sn[7], | ||
474 | sn[8], sn[9], sn[10], sn[11], | ||
475 | sn[12], sn[13], sn[14], sn[15]); | ||
476 | } | ||
477 | DEVICE_ATTR(unique_id, S_IRUGO, dev_show_unique_id, NULL); | ||
478 | |||
479 | static ssize_t dev_show_vendor(struct device *dev, | ||
480 | struct device_attribute *attr, | ||
481 | char *buf) | ||
482 | { | ||
483 | drive_info_struct *drv = to_drv(dev); | ||
484 | struct ctlr_info *h = to_hba(drv->dev.parent); | ||
485 | char vendor[VENDOR_LEN + 1]; | ||
486 | unsigned long flags; | ||
487 | int ret = 0; | ||
488 | |||
489 | spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); | ||
490 | if (h->busy_configuring) | ||
491 | ret = -EBUSY; | ||
492 | else | ||
493 | memcpy(vendor, drv->vendor, VENDOR_LEN + 1); | ||
494 | spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); | ||
495 | |||
496 | if (ret) | ||
497 | return ret; | ||
498 | else | ||
499 | return snprintf(buf, sizeof(vendor) + 1, "%s\n", drv->vendor); | ||
500 | } | ||
501 | DEVICE_ATTR(vendor, S_IRUGO, dev_show_vendor, NULL); | ||
502 | |||
503 | static ssize_t dev_show_model(struct device *dev, | ||
504 | struct device_attribute *attr, | ||
505 | char *buf) | ||
506 | { | ||
507 | drive_info_struct *drv = to_drv(dev); | ||
508 | struct ctlr_info *h = to_hba(drv->dev.parent); | ||
509 | char model[MODEL_LEN + 1]; | ||
510 | unsigned long flags; | ||
511 | int ret = 0; | ||
512 | |||
513 | spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); | ||
514 | if (h->busy_configuring) | ||
515 | ret = -EBUSY; | ||
516 | else | ||
517 | memcpy(model, drv->model, MODEL_LEN + 1); | ||
518 | spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); | ||
519 | |||
520 | if (ret) | ||
521 | return ret; | ||
522 | else | ||
523 | return snprintf(buf, sizeof(model) + 1, "%s\n", drv->model); | ||
524 | } | ||
525 | DEVICE_ATTR(model, S_IRUGO, dev_show_model, NULL); | ||
526 | |||
527 | static ssize_t dev_show_rev(struct device *dev, | ||
528 | struct device_attribute *attr, | ||
529 | char *buf) | ||
530 | { | ||
531 | drive_info_struct *drv = to_drv(dev); | ||
532 | struct ctlr_info *h = to_hba(drv->dev.parent); | ||
533 | char rev[REV_LEN + 1]; | ||
534 | unsigned long flags; | ||
535 | int ret = 0; | ||
536 | |||
537 | spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); | ||
538 | if (h->busy_configuring) | ||
539 | ret = -EBUSY; | ||
540 | else | ||
541 | memcpy(rev, drv->rev, REV_LEN + 1); | ||
542 | spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); | ||
543 | |||
544 | if (ret) | ||
545 | return ret; | ||
546 | else | ||
547 | return snprintf(buf, sizeof(rev) + 1, "%s\n", drv->rev); | ||
548 | } | ||
549 | DEVICE_ATTR(rev, S_IRUGO, dev_show_rev, NULL); | ||
550 | |||
551 | static struct attribute *cciss_dev_attrs[] = { | ||
552 | &dev_attr_unique_id.attr, | ||
553 | &dev_attr_model.attr, | ||
554 | &dev_attr_vendor.attr, | ||
555 | &dev_attr_rev.attr, | ||
556 | NULL | ||
557 | }; | ||
558 | |||
559 | static struct attribute_group cciss_dev_attr_group = { | ||
560 | .attrs = cciss_dev_attrs, | ||
561 | }; | ||
562 | |||
563 | static struct attribute_group *cciss_dev_attr_groups[] = { | ||
564 | &cciss_dev_attr_group, | ||
565 | NULL | ||
566 | }; | ||
567 | |||
568 | static struct device_type cciss_dev_type = { | ||
569 | .name = "cciss_device", | ||
570 | .groups = cciss_dev_attr_groups, | ||
571 | }; | ||
572 | |||
573 | static struct bus_type cciss_bus_type = { | ||
574 | .name = "cciss", | ||
575 | }; | ||
576 | |||
577 | |||
578 | /* | ||
579 | * Initialize sysfs entry for each controller. This sets up and registers | ||
580 | * the 'cciss#' directory for each individual controller under | ||
581 | * /sys/bus/pci/devices/<dev>/. | ||
582 | */ | ||
583 | static int cciss_create_hba_sysfs_entry(struct ctlr_info *h) | ||
584 | { | ||
585 | device_initialize(&h->dev); | ||
586 | h->dev.type = &cciss_host_type; | ||
587 | h->dev.bus = &cciss_bus_type; | ||
588 | dev_set_name(&h->dev, "%s", h->devname); | ||
589 | h->dev.parent = &h->pdev->dev; | ||
590 | |||
591 | return device_add(&h->dev); | ||
592 | } | ||
593 | |||
594 | /* | ||
595 | * Remove sysfs entries for an hba. | ||
596 | */ | ||
597 | static void cciss_destroy_hba_sysfs_entry(struct ctlr_info *h) | ||
598 | { | ||
599 | device_del(&h->dev); | ||
600 | } | ||
601 | |||
602 | /* | ||
603 | * Initialize sysfs for each logical drive. This sets up and registers | ||
604 | * the 'c#d#' directory for each individual logical drive under | ||
605 | * /sys/bus/pci/devices/<dev/ccis#/. We also create a link from | ||
606 | * /sys/block/cciss!c#d# to this entry. | ||
607 | */ | ||
608 | static int cciss_create_ld_sysfs_entry(struct ctlr_info *h, | ||
609 | drive_info_struct *drv, | ||
610 | int drv_index) | ||
611 | { | ||
612 | device_initialize(&drv->dev); | ||
613 | drv->dev.type = &cciss_dev_type; | ||
614 | drv->dev.bus = &cciss_bus_type; | ||
615 | dev_set_name(&drv->dev, "c%dd%d", h->ctlr, drv_index); | ||
616 | drv->dev.parent = &h->dev; | ||
617 | return device_add(&drv->dev); | ||
618 | } | ||
619 | |||
620 | /* | ||
621 | * Remove sysfs entries for a logical drive. | ||
622 | */ | ||
623 | static void cciss_destroy_ld_sysfs_entry(drive_info_struct *drv) | ||
624 | { | ||
625 | device_del(&drv->dev); | ||
626 | } | ||
627 | |||
440 | /* | 628 | /* |
441 | * For operations that cannot sleep, a command block is allocated at init, | 629 | * For operations that cannot sleep, a command block is allocated at init, |
442 | * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track | 630 | * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track |
@@ -1332,6 +1520,45 @@ static void cciss_softirq_done(struct request *rq) | |||
1332 | spin_unlock_irqrestore(&h->lock, flags); | 1520 | spin_unlock_irqrestore(&h->lock, flags); |
1333 | } | 1521 | } |
1334 | 1522 | ||
1523 | /* This function gets the SCSI vendor, model, and revision of a logical drive | ||
1524 | * via the inquiry page 0. Model, vendor, and rev are set to empty strings if | ||
1525 | * they cannot be read. | ||
1526 | */ | ||
1527 | static void cciss_get_device_descr(int ctlr, int logvol, int withirq, | ||
1528 | char *vendor, char *model, char *rev) | ||
1529 | { | ||
1530 | int rc; | ||
1531 | InquiryData_struct *inq_buf; | ||
1532 | |||
1533 | *vendor = '\0'; | ||
1534 | *model = '\0'; | ||
1535 | *rev = '\0'; | ||
1536 | |||
1537 | inq_buf = kzalloc(sizeof(InquiryData_struct), GFP_KERNEL); | ||
1538 | if (!inq_buf) | ||
1539 | return; | ||
1540 | |||
1541 | if (withirq) | ||
1542 | rc = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buf, | ||
1543 | sizeof(InquiryData_struct), 1, logvol, | ||
1544 | 0, TYPE_CMD); | ||
1545 | else | ||
1546 | rc = sendcmd(CISS_INQUIRY, ctlr, inq_buf, | ||
1547 | sizeof(InquiryData_struct), 1, logvol, 0, NULL, | ||
1548 | TYPE_CMD); | ||
1549 | if (rc == IO_OK) { | ||
1550 | memcpy(vendor, &inq_buf->data_byte[8], VENDOR_LEN); | ||
1551 | vendor[VENDOR_LEN] = '\0'; | ||
1552 | memcpy(model, &inq_buf->data_byte[16], MODEL_LEN); | ||
1553 | model[MODEL_LEN] = '\0'; | ||
1554 | memcpy(rev, &inq_buf->data_byte[32], REV_LEN); | ||
1555 | rev[REV_LEN] = '\0'; | ||
1556 | } | ||
1557 | |||
1558 | kfree(inq_buf); | ||
1559 | return; | ||
1560 | } | ||
1561 | |||
1335 | /* This function gets the serial number of a logical drive via | 1562 | /* This function gets the serial number of a logical drive via |
1336 | * inquiry page 0x83. Serial no. is 16 bytes. If the serial | 1563 | * inquiry page 0x83. Serial no. is 16 bytes. If the serial |
1337 | * number cannot be had, for whatever reason, 16 bytes of 0xff | 1564 | * number cannot be had, for whatever reason, 16 bytes of 0xff |
@@ -1372,7 +1599,7 @@ static void cciss_add_disk(ctlr_info_t *h, struct gendisk *disk, | |||
1372 | disk->first_minor = drv_index << NWD_SHIFT; | 1599 | disk->first_minor = drv_index << NWD_SHIFT; |
1373 | disk->fops = &cciss_fops; | 1600 | disk->fops = &cciss_fops; |
1374 | disk->private_data = &h->drv[drv_index]; | 1601 | disk->private_data = &h->drv[drv_index]; |
1375 | disk->driverfs_dev = &h->pdev->dev; | 1602 | disk->driverfs_dev = &h->drv[drv_index].dev; |
1376 | 1603 | ||
1377 | /* Set up queue information */ | 1604 | /* Set up queue information */ |
1378 | blk_queue_bounce_limit(disk->queue, h->pdev->dma_mask); | 1605 | blk_queue_bounce_limit(disk->queue, h->pdev->dma_mask); |
@@ -1463,6 +1690,8 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time) | |||
1463 | drvinfo->block_size = block_size; | 1690 | drvinfo->block_size = block_size; |
1464 | drvinfo->nr_blocks = total_size + 1; | 1691 | drvinfo->nr_blocks = total_size + 1; |
1465 | 1692 | ||
1693 | cciss_get_device_descr(ctlr, drv_index, 1, drvinfo->vendor, | ||
1694 | drvinfo->model, drvinfo->rev); | ||
1466 | cciss_get_serial_no(ctlr, drv_index, 1, drvinfo->serial_no, | 1695 | cciss_get_serial_no(ctlr, drv_index, 1, drvinfo->serial_no, |
1467 | sizeof(drvinfo->serial_no)); | 1696 | sizeof(drvinfo->serial_no)); |
1468 | 1697 | ||
@@ -1512,6 +1741,9 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time) | |||
1512 | h->drv[drv_index].cylinders = drvinfo->cylinders; | 1741 | h->drv[drv_index].cylinders = drvinfo->cylinders; |
1513 | h->drv[drv_index].raid_level = drvinfo->raid_level; | 1742 | h->drv[drv_index].raid_level = drvinfo->raid_level; |
1514 | memcpy(h->drv[drv_index].serial_no, drvinfo->serial_no, 16); | 1743 | memcpy(h->drv[drv_index].serial_no, drvinfo->serial_no, 16); |
1744 | memcpy(h->drv[drv_index].vendor, drvinfo->vendor, VENDOR_LEN + 1); | ||
1745 | memcpy(h->drv[drv_index].model, drvinfo->model, MODEL_LEN + 1); | ||
1746 | memcpy(h->drv[drv_index].rev, drvinfo->rev, REV_LEN + 1); | ||
1515 | 1747 | ||
1516 | ++h->num_luns; | 1748 | ++h->num_luns; |
1517 | disk = h->gendisk[drv_index]; | 1749 | disk = h->gendisk[drv_index]; |
@@ -1586,6 +1818,8 @@ static int cciss_add_gendisk(ctlr_info_t *h, __u32 lunid, int controller_node) | |||
1586 | } | 1818 | } |
1587 | } | 1819 | } |
1588 | h->drv[drv_index].LunID = lunid; | 1820 | h->drv[drv_index].LunID = lunid; |
1821 | if (cciss_create_ld_sysfs_entry(h, &h->drv[drv_index], drv_index)) | ||
1822 | goto err_free_disk; | ||
1589 | 1823 | ||
1590 | /* Don't need to mark this busy because nobody */ | 1824 | /* Don't need to mark this busy because nobody */ |
1591 | /* else knows about this disk yet to contend */ | 1825 | /* else knows about this disk yet to contend */ |
@@ -1593,6 +1827,11 @@ static int cciss_add_gendisk(ctlr_info_t *h, __u32 lunid, int controller_node) | |||
1593 | h->drv[drv_index].busy_configuring = 0; | 1827 | h->drv[drv_index].busy_configuring = 0; |
1594 | wmb(); | 1828 | wmb(); |
1595 | return drv_index; | 1829 | return drv_index; |
1830 | |||
1831 | err_free_disk: | ||
1832 | put_disk(h->gendisk[drv_index]); | ||
1833 | h->gendisk[drv_index] = NULL; | ||
1834 | return -1; | ||
1596 | } | 1835 | } |
1597 | 1836 | ||
1598 | /* This is for the special case of a controller which | 1837 | /* This is for the special case of a controller which |
@@ -1713,6 +1952,7 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time) | |||
1713 | h->drv[i].busy_configuring = 1; | 1952 | h->drv[i].busy_configuring = 1; |
1714 | spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); | 1953 | spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); |
1715 | return_code = deregister_disk(h, i, 1); | 1954 | return_code = deregister_disk(h, i, 1); |
1955 | cciss_destroy_ld_sysfs_entry(&h->drv[i]); | ||
1716 | h->drv[i].busy_configuring = 0; | 1956 | h->drv[i].busy_configuring = 0; |
1717 | } | 1957 | } |
1718 | } | 1958 | } |
@@ -3719,12 +3959,15 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, | |||
3719 | INIT_HLIST_HEAD(&hba[i]->reqQ); | 3959 | INIT_HLIST_HEAD(&hba[i]->reqQ); |
3720 | 3960 | ||
3721 | if (cciss_pci_init(hba[i], pdev) != 0) | 3961 | if (cciss_pci_init(hba[i], pdev) != 0) |
3722 | goto clean1; | 3962 | goto clean0; |
3723 | 3963 | ||
3724 | sprintf(hba[i]->devname, "cciss%d", i); | 3964 | sprintf(hba[i]->devname, "cciss%d", i); |
3725 | hba[i]->ctlr = i; | 3965 | hba[i]->ctlr = i; |
3726 | hba[i]->pdev = pdev; | 3966 | hba[i]->pdev = pdev; |
3727 | 3967 | ||
3968 | if (cciss_create_hba_sysfs_entry(hba[i])) | ||
3969 | goto clean0; | ||
3970 | |||
3728 | /* configure PCI DMA stuff */ | 3971 | /* configure PCI DMA stuff */ |
3729 | if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) | 3972 | if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) |
3730 | dac = 1; | 3973 | dac = 1; |
@@ -3868,6 +4111,8 @@ clean4: | |||
3868 | clean2: | 4111 | clean2: |
3869 | unregister_blkdev(hba[i]->major, hba[i]->devname); | 4112 | unregister_blkdev(hba[i]->major, hba[i]->devname); |
3870 | clean1: | 4113 | clean1: |
4114 | cciss_destroy_hba_sysfs_entry(hba[i]); | ||
4115 | clean0: | ||
3871 | hba[i]->busy_initializing = 0; | 4116 | hba[i]->busy_initializing = 0; |
3872 | /* cleanup any queues that may have been initialized */ | 4117 | /* cleanup any queues that may have been initialized */ |
3873 | for (j=0; j <= hba[i]->highest_lun; j++){ | 4118 | for (j=0; j <= hba[i]->highest_lun; j++){ |
@@ -3978,6 +4223,7 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev) | |||
3978 | */ | 4223 | */ |
3979 | pci_release_regions(pdev); | 4224 | pci_release_regions(pdev); |
3980 | pci_set_drvdata(pdev, NULL); | 4225 | pci_set_drvdata(pdev, NULL); |
4226 | cciss_destroy_hba_sysfs_entry(hba[i]); | ||
3981 | free_hba(i); | 4227 | free_hba(i); |
3982 | } | 4228 | } |
3983 | 4229 | ||
@@ -3995,6 +4241,8 @@ static struct pci_driver cciss_pci_driver = { | |||
3995 | */ | 4241 | */ |
3996 | static int __init cciss_init(void) | 4242 | static int __init cciss_init(void) |
3997 | { | 4243 | { |
4244 | int err; | ||
4245 | |||
3998 | /* | 4246 | /* |
3999 | * The hardware requires that commands are aligned on a 64-bit | 4247 | * The hardware requires that commands are aligned on a 64-bit |
4000 | * boundary. Given that we use pci_alloc_consistent() to allocate an | 4248 | * boundary. Given that we use pci_alloc_consistent() to allocate an |
@@ -4004,8 +4252,20 @@ static int __init cciss_init(void) | |||
4004 | 4252 | ||
4005 | printk(KERN_INFO DRIVER_NAME "\n"); | 4253 | printk(KERN_INFO DRIVER_NAME "\n"); |
4006 | 4254 | ||
4255 | err = bus_register(&cciss_bus_type); | ||
4256 | if (err) | ||
4257 | return err; | ||
4258 | |||
4007 | /* Register for our PCI devices */ | 4259 | /* Register for our PCI devices */ |
4008 | return pci_register_driver(&cciss_pci_driver); | 4260 | err = pci_register_driver(&cciss_pci_driver); |
4261 | if (err) | ||
4262 | goto err_bus_register; | ||
4263 | |||
4264 | return 0; | ||
4265 | |||
4266 | err_bus_register: | ||
4267 | bus_unregister(&cciss_bus_type); | ||
4268 | return err; | ||
4009 | } | 4269 | } |
4010 | 4270 | ||
4011 | static void __exit cciss_cleanup(void) | 4271 | static void __exit cciss_cleanup(void) |
@@ -4022,6 +4282,7 @@ static void __exit cciss_cleanup(void) | |||
4022 | } | 4282 | } |
4023 | } | 4283 | } |
4024 | remove_proc_entry("driver/cciss", NULL); | 4284 | remove_proc_entry("driver/cciss", NULL); |
4285 | bus_unregister(&cciss_bus_type); | ||
4025 | } | 4286 | } |
4026 | 4287 | ||
4027 | static void fail_all_cmds(unsigned long ctlr) | 4288 | static void fail_all_cmds(unsigned long ctlr) |