diff options
author | Aaro Koskinen <Aaro.Koskinen@nokia.com> | 2009-04-14 16:47:00 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-05-20 18:21:14 -0400 |
commit | fa8584566cc9cdaf067dbc12132792887a521da9 (patch) | |
tree | e103d0c9b1885ad8c017ea5f20b7881f06e85239 /drivers/scsi/sym53c8xx_2/sym_glue.c | |
parent | 410604d25faddb1b4f0f9667b7452c06cc06cea1 (diff) |
[SCSI] sym53c8xx_2: slave_alloc/destroy safety (2.6.27.5)
Make the sym53c8xx_2 driver slave_alloc/destroy less unsafe. References
to the destroyed LCB are cleared from the target structure (instead of
leaving a dangling pointer), and when the last LCB for the target is
destroyed the reference to the upper layer target data is cleared. The
host lock is used to prevent a race with the interrupt handler. Also
user commands are prevented for targets with all LCBs destroyed.
Signed-off-by: Aaro Koskinen <Aaro.Koskinen@nokia.com>
Tested-by: Tony Battersby <tonyb@cybernetics.com>
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/sym53c8xx_2/sym_glue.c')
-rw-r--r-- | drivers/scsi/sym53c8xx_2/sym_glue.c | 66 |
1 files changed, 52 insertions, 14 deletions
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index 583966ec8266..45374d66d26a 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c | |||
@@ -737,11 +737,14 @@ static int sym53c8xx_slave_alloc(struct scsi_device *sdev) | |||
737 | struct sym_hcb *np = sym_get_hcb(sdev->host); | 737 | struct sym_hcb *np = sym_get_hcb(sdev->host); |
738 | struct sym_tcb *tp = &np->target[sdev->id]; | 738 | struct sym_tcb *tp = &np->target[sdev->id]; |
739 | struct sym_lcb *lp; | 739 | struct sym_lcb *lp; |
740 | unsigned long flags; | ||
741 | int error; | ||
740 | 742 | ||
741 | if (sdev->id >= SYM_CONF_MAX_TARGET || sdev->lun >= SYM_CONF_MAX_LUN) | 743 | if (sdev->id >= SYM_CONF_MAX_TARGET || sdev->lun >= SYM_CONF_MAX_LUN) |
742 | return -ENXIO; | 744 | return -ENXIO; |
743 | 745 | ||
744 | tp->starget = sdev->sdev_target; | 746 | spin_lock_irqsave(np->s.host->host_lock, flags); |
747 | |||
745 | /* | 748 | /* |
746 | * Fail the device init if the device is flagged NOSCAN at BOOT in | 749 | * Fail the device init if the device is flagged NOSCAN at BOOT in |
747 | * the NVRAM. This may speed up boot and maintain coherency with | 750 | * the NVRAM. This may speed up boot and maintain coherency with |
@@ -753,26 +756,37 @@ static int sym53c8xx_slave_alloc(struct scsi_device *sdev) | |||
753 | 756 | ||
754 | if (tp->usrflags & SYM_SCAN_BOOT_DISABLED) { | 757 | if (tp->usrflags & SYM_SCAN_BOOT_DISABLED) { |
755 | tp->usrflags &= ~SYM_SCAN_BOOT_DISABLED; | 758 | tp->usrflags &= ~SYM_SCAN_BOOT_DISABLED; |
756 | starget_printk(KERN_INFO, tp->starget, | 759 | starget_printk(KERN_INFO, sdev->sdev_target, |
757 | "Scan at boot disabled in NVRAM\n"); | 760 | "Scan at boot disabled in NVRAM\n"); |
758 | return -ENXIO; | 761 | error = -ENXIO; |
762 | goto out; | ||
759 | } | 763 | } |
760 | 764 | ||
761 | if (tp->usrflags & SYM_SCAN_LUNS_DISABLED) { | 765 | if (tp->usrflags & SYM_SCAN_LUNS_DISABLED) { |
762 | if (sdev->lun != 0) | 766 | if (sdev->lun != 0) { |
763 | return -ENXIO; | 767 | error = -ENXIO; |
764 | starget_printk(KERN_INFO, tp->starget, | 768 | goto out; |
769 | } | ||
770 | starget_printk(KERN_INFO, sdev->sdev_target, | ||
765 | "Multiple LUNs disabled in NVRAM\n"); | 771 | "Multiple LUNs disabled in NVRAM\n"); |
766 | } | 772 | } |
767 | 773 | ||
768 | lp = sym_alloc_lcb(np, sdev->id, sdev->lun); | 774 | lp = sym_alloc_lcb(np, sdev->id, sdev->lun); |
769 | if (!lp) | 775 | if (!lp) { |
770 | return -ENOMEM; | 776 | error = -ENOMEM; |
777 | goto out; | ||
778 | } | ||
779 | if (tp->nlcb == 1) | ||
780 | tp->starget = sdev->sdev_target; | ||
771 | 781 | ||
772 | spi_min_period(tp->starget) = tp->usr_period; | 782 | spi_min_period(tp->starget) = tp->usr_period; |
773 | spi_max_width(tp->starget) = tp->usr_width; | 783 | spi_max_width(tp->starget) = tp->usr_width; |
774 | 784 | ||
775 | return 0; | 785 | error = 0; |
786 | out: | ||
787 | spin_unlock_irqrestore(np->s.host->host_lock, flags); | ||
788 | |||
789 | return error; | ||
776 | } | 790 | } |
777 | 791 | ||
778 | /* | 792 | /* |
@@ -819,12 +833,34 @@ static int sym53c8xx_slave_configure(struct scsi_device *sdev) | |||
819 | static void sym53c8xx_slave_destroy(struct scsi_device *sdev) | 833 | static void sym53c8xx_slave_destroy(struct scsi_device *sdev) |
820 | { | 834 | { |
821 | struct sym_hcb *np = sym_get_hcb(sdev->host); | 835 | struct sym_hcb *np = sym_get_hcb(sdev->host); |
822 | struct sym_lcb *lp = sym_lp(&np->target[sdev->id], sdev->lun); | 836 | struct sym_tcb *tp = &np->target[sdev->id]; |
837 | struct sym_lcb *lp = sym_lp(tp, sdev->lun); | ||
838 | unsigned long flags; | ||
839 | |||
840 | spin_lock_irqsave(np->s.host->host_lock, flags); | ||
841 | |||
842 | if (lp->busy_itlq || lp->busy_itl) { | ||
843 | /* | ||
844 | * This really shouldn't happen, but we can't return an error | ||
845 | * so let's try to stop all on-going I/O. | ||
846 | */ | ||
847 | starget_printk(KERN_WARNING, tp->starget, | ||
848 | "Removing busy LCB (%d)\n", sdev->lun); | ||
849 | sym_reset_scsi_bus(np, 1); | ||
850 | } | ||
823 | 851 | ||
824 | if (lp->itlq_tbl) | 852 | if (sym_free_lcb(np, sdev->id, sdev->lun) == 0) { |
825 | sym_mfree_dma(lp->itlq_tbl, SYM_CONF_MAX_TASK * 4, "ITLQ_TBL"); | 853 | /* |
826 | kfree(lp->cb_tags); | 854 | * It was the last unit for this target. |
827 | sym_mfree_dma(lp, sizeof(*lp), "LCB"); | 855 | */ |
856 | tp->head.sval = 0; | ||
857 | tp->head.wval = np->rv_scntl3; | ||
858 | tp->head.uval = 0; | ||
859 | tp->tgoal.check_nego = 1; | ||
860 | tp->starget = NULL; | ||
861 | } | ||
862 | |||
863 | spin_unlock_irqrestore(np->s.host->host_lock, flags); | ||
828 | } | 864 | } |
829 | 865 | ||
830 | /* | 866 | /* |
@@ -890,6 +926,8 @@ static void sym_exec_user_command (struct sym_hcb *np, struct sym_usrcmd *uc) | |||
890 | if (!((uc->target >> t) & 1)) | 926 | if (!((uc->target >> t) & 1)) |
891 | continue; | 927 | continue; |
892 | tp = &np->target[t]; | 928 | tp = &np->target[t]; |
929 | if (!tp->nlcb) | ||
930 | continue; | ||
893 | 931 | ||
894 | switch (uc->cmd) { | 932 | switch (uc->cmd) { |
895 | 933 | ||