diff options
author | Joe Carnuccio <joe.carnuccio@qlogic.com> | 2009-03-24 12:08:12 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-04-03 10:22:51 -0400 |
commit | ad0ecd61f4ad3260ca8f7216765ddbb1a10677ea (patch) | |
tree | 4a228bd11305a1c07647b948e571542ac9b9389c /drivers/scsi/qla2xxx/qla_attr.c | |
parent | fbcbb5d0cf69ba8b59028ec3c5b9f9ff04409b88 (diff) |
[SCSI] qla2xxx: Add EDC-update support.
Interface allows for the update of onboard EDC firmware
present on mezzanine ISP25xx type cards.
Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_attr.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_attr.c | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index c017dba90039..877990115f53 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c | |||
@@ -548,6 +548,144 @@ static struct bin_attribute sysfs_reset_attr = { | |||
548 | .write = qla2x00_sysfs_write_reset, | 548 | .write = qla2x00_sysfs_write_reset, |
549 | }; | 549 | }; |
550 | 550 | ||
551 | static ssize_t | ||
552 | qla2x00_sysfs_write_edc(struct kobject *kobj, | ||
553 | struct bin_attribute *bin_attr, | ||
554 | char *buf, loff_t off, size_t count) | ||
555 | { | ||
556 | struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, | ||
557 | struct device, kobj))); | ||
558 | struct qla_hw_data *ha = vha->hw; | ||
559 | uint16_t dev, adr, opt, len; | ||
560 | int rval; | ||
561 | |||
562 | ha->edc_data_len = 0; | ||
563 | |||
564 | if (!capable(CAP_SYS_ADMIN) || off != 0 || count < 8) | ||
565 | return 0; | ||
566 | |||
567 | if (!ha->edc_data) { | ||
568 | ha->edc_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, | ||
569 | &ha->edc_data_dma); | ||
570 | if (!ha->edc_data) { | ||
571 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
572 | "Unable to allocate memory for EDC write.\n")); | ||
573 | return 0; | ||
574 | } | ||
575 | } | ||
576 | |||
577 | dev = le16_to_cpup((void *)&buf[0]); | ||
578 | adr = le16_to_cpup((void *)&buf[2]); | ||
579 | opt = le16_to_cpup((void *)&buf[4]); | ||
580 | len = le16_to_cpup((void *)&buf[6]); | ||
581 | |||
582 | if (!(opt & BIT_0)) | ||
583 | if (len == 0 || len > DMA_POOL_SIZE || len > count - 8) | ||
584 | return -EINVAL; | ||
585 | |||
586 | memcpy(ha->edc_data, &buf[8], len); | ||
587 | |||
588 | rval = qla2x00_write_edc(vha, dev, adr, ha->edc_data_dma, | ||
589 | ha->edc_data, len, opt); | ||
590 | if (rval != QLA_SUCCESS) { | ||
591 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
592 | "Unable to write EDC (%x) %02x:%02x:%04x:%02x:%02x.\n", | ||
593 | rval, dev, adr, opt, len, *buf)); | ||
594 | return 0; | ||
595 | } | ||
596 | |||
597 | return count; | ||
598 | } | ||
599 | |||
600 | static struct bin_attribute sysfs_edc_attr = { | ||
601 | .attr = { | ||
602 | .name = "edc", | ||
603 | .mode = S_IWUSR, | ||
604 | }, | ||
605 | .size = 0, | ||
606 | .write = qla2x00_sysfs_write_edc, | ||
607 | }; | ||
608 | |||
609 | static ssize_t | ||
610 | qla2x00_sysfs_write_edc_status(struct kobject *kobj, | ||
611 | struct bin_attribute *bin_attr, | ||
612 | char *buf, loff_t off, size_t count) | ||
613 | { | ||
614 | struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, | ||
615 | struct device, kobj))); | ||
616 | struct qla_hw_data *ha = vha->hw; | ||
617 | uint16_t dev, adr, opt, len; | ||
618 | int rval; | ||
619 | |||
620 | ha->edc_data_len = 0; | ||
621 | |||
622 | if (!capable(CAP_SYS_ADMIN) || off != 0 || count < 8) | ||
623 | return 0; | ||
624 | |||
625 | if (!ha->edc_data) { | ||
626 | ha->edc_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, | ||
627 | &ha->edc_data_dma); | ||
628 | if (!ha->edc_data) { | ||
629 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
630 | "Unable to allocate memory for EDC status.\n")); | ||
631 | return 0; | ||
632 | } | ||
633 | } | ||
634 | |||
635 | dev = le16_to_cpup((void *)&buf[0]); | ||
636 | adr = le16_to_cpup((void *)&buf[2]); | ||
637 | opt = le16_to_cpup((void *)&buf[4]); | ||
638 | len = le16_to_cpup((void *)&buf[6]); | ||
639 | |||
640 | if (!(opt & BIT_0)) | ||
641 | if (len == 0 || len > DMA_POOL_SIZE) | ||
642 | return -EINVAL; | ||
643 | |||
644 | memset(ha->edc_data, 0, len); | ||
645 | rval = qla2x00_read_edc(vha, dev, adr, ha->edc_data_dma, | ||
646 | ha->edc_data, len, opt); | ||
647 | if (rval != QLA_SUCCESS) { | ||
648 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
649 | "Unable to write EDC status (%x) %02x:%02x:%04x:%02x.\n", | ||
650 | rval, dev, adr, opt, len)); | ||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | ha->edc_data_len = len; | ||
655 | |||
656 | return count; | ||
657 | } | ||
658 | |||
659 | static ssize_t | ||
660 | qla2x00_sysfs_read_edc_status(struct kobject *kobj, | ||
661 | struct bin_attribute *bin_attr, | ||
662 | char *buf, loff_t off, size_t count) | ||
663 | { | ||
664 | struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, | ||
665 | struct device, kobj))); | ||
666 | struct qla_hw_data *ha = vha->hw; | ||
667 | |||
668 | if (!capable(CAP_SYS_ADMIN) || off != 0 || count == 0) | ||
669 | return 0; | ||
670 | |||
671 | if (!ha->edc_data || ha->edc_data_len == 0 || ha->edc_data_len > count) | ||
672 | return -EINVAL; | ||
673 | |||
674 | memcpy(buf, ha->edc_data, ha->edc_data_len); | ||
675 | |||
676 | return ha->edc_data_len; | ||
677 | } | ||
678 | |||
679 | static struct bin_attribute sysfs_edc_status_attr = { | ||
680 | .attr = { | ||
681 | .name = "edc_status", | ||
682 | .mode = S_IRUSR | S_IWUSR, | ||
683 | }, | ||
684 | .size = 0, | ||
685 | .write = qla2x00_sysfs_write_edc_status, | ||
686 | .read = qla2x00_sysfs_read_edc_status, | ||
687 | }; | ||
688 | |||
551 | static struct sysfs_entry { | 689 | static struct sysfs_entry { |
552 | char *name; | 690 | char *name; |
553 | struct bin_attribute *attr; | 691 | struct bin_attribute *attr; |
@@ -560,6 +698,8 @@ static struct sysfs_entry { | |||
560 | { "vpd", &sysfs_vpd_attr, 1 }, | 698 | { "vpd", &sysfs_vpd_attr, 1 }, |
561 | { "sfp", &sysfs_sfp_attr, 1 }, | 699 | { "sfp", &sysfs_sfp_attr, 1 }, |
562 | { "reset", &sysfs_reset_attr, }, | 700 | { "reset", &sysfs_reset_attr, }, |
701 | { "edc", &sysfs_edc_attr, 2 }, | ||
702 | { "edc_status", &sysfs_edc_status_attr, 2 }, | ||
563 | { NULL }, | 703 | { NULL }, |
564 | }; | 704 | }; |
565 | 705 | ||
@@ -573,6 +713,8 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *vha) | |||
573 | for (iter = bin_file_entries; iter->name; iter++) { | 713 | for (iter = bin_file_entries; iter->name; iter++) { |
574 | if (iter->is4GBp_only && !IS_FWI2_CAPABLE(vha->hw)) | 714 | if (iter->is4GBp_only && !IS_FWI2_CAPABLE(vha->hw)) |
575 | continue; | 715 | continue; |
716 | if (iter->is4GBp_only == 2 && !IS_QLA25XX(vha->hw)) | ||
717 | continue; | ||
576 | 718 | ||
577 | ret = sysfs_create_bin_file(&host->shost_gendev.kobj, | 719 | ret = sysfs_create_bin_file(&host->shost_gendev.kobj, |
578 | iter->attr); | 720 | iter->attr); |
@@ -593,6 +735,8 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *vha) | |||
593 | for (iter = bin_file_entries; iter->name; iter++) { | 735 | for (iter = bin_file_entries; iter->name; iter++) { |
594 | if (iter->is4GBp_only && !IS_FWI2_CAPABLE(ha)) | 736 | if (iter->is4GBp_only && !IS_FWI2_CAPABLE(ha)) |
595 | continue; | 737 | continue; |
738 | if (iter->is4GBp_only == 2 && !IS_QLA25XX(ha)) | ||
739 | continue; | ||
596 | 740 | ||
597 | sysfs_remove_bin_file(&host->shost_gendev.kobj, | 741 | sysfs_remove_bin_file(&host->shost_gendev.kobj, |
598 | iter->attr); | 742 | iter->attr); |